2012-12-07 34 views
7

我試圖在Ruby中「複製」CUDA的__synchtreads()函數的行爲。具體來說,我有一組N線程需要執行一些代碼,然後在執行其他業務之前,在執行的中間點彼此等待。例如:在Ruby中實現同步屏障

x = 0 

a = Thread.new do 
    x = 1 
    syncthreads() 
end 

b = Thread.new do 
    syncthreads() 
    # x should have been changed 
    raise if x == 0 
end 

[a,b].each { |t| t.join } 

需要使用哪些工具來完成此操作?我嘗試使用全局散列,然後休眠,直到所有線程都設置了一個標誌,表明它們已完成代碼的第一部分。我無法讓它正常工作;它導致了掛起和僵局。我認爲我需要使用MutexConditionVariable的組合,但我不確定爲什麼/如何。

編輯: 50 views and no answer!看起來像一個賞金的候選人...

+0

@sawa我在上面的代碼展示中發現了這個錯誤,並且它能夠正常工作,但我願意提供更清晰的建議。睡覺()被認爲是不好的習慣? – user2398029

+0

'睡眠'不是一個好習慣。這不是你應該完全避免的,但儘可能避免。我有這種感覺,你可以通過'Thread#join'或者使用'Fiber'。 – sawa

+0

謝謝,我將添加'fiber'作爲標籤。 – user2398029

回答

7

讓我們實現一個同步障礙。它必須知道它將處理的線程數量,預先處理的數量爲n。在第一個n - 1調用sync屏障將導致調用線程等待。電話號碼n將喚醒所有線程。

class Barrier 
    def initialize(count) 
    @mutex = Mutex.new 
    @cond = ConditionVariable.new 
    @count = count 
    end 

    def sync 
    @mutex.synchronize do 
     @count -= 1 
     if @count > 0 
     @cond.wait @mutex 
     else 
     @cond.broadcast 
     end 
    end 
    end 
end 

整體sync是一個關鍵部分,即它不能同時由兩個線程執行。因此致電Mutex#synchronize

當減值@count爲正值時,線程被凍結。將互斥量作爲參數傳遞給ConditionVariable#wait是防止死鎖的關鍵。它會在凍結線程之前解鎖互斥體。

一個簡單的實驗啓動1k個線程,並使它們添加元素到一個數組。首先他們添加零,然後他們同步和添加。預期的結果是一個有2k個元素的排序數組,其中1k是零,1k是1。

mtx = Mutex.new 
arr = [] 
num = 1000 
barrier = Barrier.new num 
num.times.map do 
    Thread.start do 
    mtx.synchronize { arr << 0 } 
    barrier.sync 
    mtx.synchronize { arr << 1 } 
    end 
end .map &:join; 
# Prints true. See it break by deleting `barrier.sync`. 
puts [ 
    arr.sort == arr, 
    arr.count == 2 * num, 
    arr.count(&:zero?) == num, 
    arr.uniq == [0, 1], 
].all? 

事實上,有a gem named barrier這正是我上面描述的。

最後一點,在這種情況下不要用睡覺來等待。它叫做忙等待is considered a bad practice

+0

不錯的答案,非常有幫助!一個問題:添加到數組時是否需要同步('array << 0')?是否有可能通過使用線程安全的數組實現來繞開這個問題,該實現使用自己的鎖?或者這種解決方案工作的必要性? – user2398029

+0

'mtx' Mutex在這裏可以確保在寫入數組的線程之間不會有任何競爭條件。你所描述的線程安全的數組也應該可以正常工作。 – Jan

0

可能有線程等待對方的優點。但我認爲讓這些線程真正在「中點」完成是更加清晰的,因爲你的問題顯然意味着線程在「中點」需要彼此的結果。清潔設計解決方案將是讓他們完成,提供他們工作的結果,並基於這些創建一套全新的線程。

+0

我同意100%,但因爲這是一個CUDA模擬器,所以它有點失敗了目的:)我可以根據靜態代碼分析來拆分內核,但我寧願不去那裏。 – user2398029

+0

在這種情況下,請不要說我之前說過的話:-) –