前幾天我遇到了一個問題,我花了 2 個小時在錯誤的地方尋找答案。
在此程序中,我將代碼精簡為以下版本。只要我sleep(0.1)在回圈中創建執行緒,這里的執行緒就可以作業。
如果省略該行,則會創建所有執行緒 - 但實際上只有執行緒 7 會消耗佇列中的資料。
有了這個“黑客”,我確實有一個可行的解決方案,但不是我滿意的解決方案。我真的很好奇為什么會這樣。
我在 windows 2.4.1p111 下使用了相當舊版本的 ruby??。但是,我能夠使用新的 ruby?? 3.0.2p107 安裝重現相同的行為
#!/usr/bin/env ruby
@q = Queue.new
# Get all projects (would be a list of directories)
projects = [*0..100]
projects.each do |project|
@q.push project
end
def worker(num)
while not @q.empty?
puts "Thread: #{num} Project: #{@q.pop}"
sleep(0.5)
end
end
threads=[]
for i in 1..7 do
threads << Thread.new { worker(i) }
sleep(0.1) # Threading does not work without this line - but why?
end
threads.each {|thread| puts thread.join }
puts "done"
uj5u.com熱心網友回復:
有趣的錯誤!這是一個競爭條件。
并不是只有執行緒 7 正在作業,而是所有執行緒都在參考記憶體中的同一個變數 i(只有一個副本!)所以因為數字 7 最后寫入(推測在任何執行緒啟動之前)它們都讀取相同i==7.
試試這個作業函式,看看它是否能解決問題
def worker(num)
my_thread_id = Thread.current.object_id
while not @q.empty?
puts "Thread: #{num} NumObjId: #{num.object_id} ThreadId: #{my_thread_id} Project: #{@q.pop}"
sleep(0.5)
end
end
請注意 NumObjId 在所有執行緒中都是相同的。他們都指向同一個數字。但是我們得到的實際 ThreadId 是不同的。
如果您確實需要每個執行緒中的數字,則分配與執行緒一樣多的數字。就像是
ids = (1..7).to_a
ids.each do |i|
threads << Thread.new { worker(i) }
end
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/318761.html
