2012-06-01 19 views
3

我具有同步的隊列,它提供一個條件變量。MonitorMixin條件變量 - >死鎖

當數據被添加到隊列即條件變量的信號。

我有5個主題:

Thread.new do 
    loop do 
    @queue.synchronize { 
     cond.wait_until { @queue.has_data? || @queue.finished? } 
    } 
    # some processing code that can also call @queue.enqueue 
    end 
end 

然後我做的:

@queue.enqueue some_data 
@threads.each(&:join) 

MyQueue#enqueue看起來是這樣的:

def enqueue(data) 
    synchronize do 
    @pending << v unless queued?(data) || processed?(data) || processing?(data) 
    data_cond.signal 
    end 
end 

def finished? 
    @started && @processing.empty? && @pending.empty? 
end 

def has_data? 
    [email protected]? 
end 

而且我得到#join

deadlock detected 

究竟這是如何導致死鎖,以及如何將一個解決?

+2

什麼是你的代碼,增加了數據樣子的? –

+0

嗨,弗雷德,我添加了#enqueue代碼 – glebm

+0

has_data/finished方法是什麼樣的? –

回答

2

我不知道這是所有線程被擋在了相同條件變量的一個問題,而心不是提供給排隊的數據線,這將釋放其他線程。

基於此代碼的註釋:即提到

Thread.new do 
    loop do 
    @queue.synchronize { 
     cond.wait_until { @queue.has_data? || @queue.finished? } 
    } 
    # some processing code that can also call @queue.enqueue 
    end 
end 

您的評論「一些處理代碼,也可以撥打@ queue.enqueue」,這是隻有在@queue.enqueue就是所謂的地方嗎?如果是這樣,那麼所有的線程將被阻塞在條件變量上,並且任何線程都不能到達能夠調用入隊的點。我確信Ruby可以檢測到所有線程都被鎖定在同一個實體上,並且沒有任何線程可以釋放它,從而導致死鎖。

如果你確實有一個單獨的線程,只有入隊(這是一個典型的生產者/消費者的情況),請確保它也犯規等待條件變量,這也可能導致死鎖。

0

無需等待has_data? ||完了嗎?在同步塊中。代碼應該如下所示:

Thread.new do 
    loop do 
    cond.wait_until { @queue.has_data? || @queue.finished? } 
    enq = nil 
    @queue.synchronize { 
     enq = @queue.pop 
    } 
    # some processing code that can also call @queue.enqueue 
    end 
end 

在這種情況下,只有在使用隊列內容進行操作時才鎖定其他線程。你需要做的是在隊列狀態變化上進行同步,比如完成

一個更好的解決方法是用所有的線程關鍵變量包含互斥量,例如rails中的here。它會使代碼變慢一點,因爲它消除了同時變量訪問。

+0

我必須在隊列上進行同步,否則我會得到'當前線程不是所有者'。我正在考慮用互斥體做這件事,但是如果我只能讓它工作,代碼將更容易理解...... – glebm

+0

實際的問題是,使用wait_until,你正在鎖定所有線程以等待一些變量,這是僵局。如果你需要鎖定它,你需要鎖定wait_until而不是在外面。正如我所提到的,你可以爲互斥鎖attrs /方法進行封裝來清理實現 – Sigurd

+2

wait_until在等待時釋放基礎互斥鎖 –

1

這一點很難幫你,因爲你只張貼代碼片段...

你應該嘗試work_queue寶石,或至少採取看看source code