线程死锁

时间:2012-02-29 00:25:15

标签: ruby multithreading deadlock

天儿真好,

我正在尝试使用ruby 1.9.3进行简单的多线程实验。

代码:

require 'thread'

ary = *0..10 

res = 0
mutex = Mutex.new
#cv = ConditionVariable.new

ary.each do |x|
    p "Iteration no. #{x}"
    t = Thread.new do
        p "Thread taking care of #{x}"
        mutex.synchronize do 
            #cv.wait(mutex)
            res += x
            t.stop
        end
    end
end

Thread.list.each do |t| t.join; end
puts res

电话

brode@curral:~/coding$ ruby --version
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
brode@curral:~/coding$ ruby mt.rb
"Iteration no. 0"
"Iteration no. 1"
"Iteration no. 2"
"Iteration no. 3"
"Iteration no. 4"
"Thread taking care of 2"
"Thread taking care of 1"
"Thread taking care of 0"
"Thread taking care of 3"
"Iteration no. 5"
"Thread taking care of 4"
"Iteration no. 6"
"Thread taking care of 5"
"Iteration no. 7"
"Thread taking care of 6"
"Iteration no. 8"
"Thread taking care of 7"
"Iteration no. 9"
"Thread taking care of 8"
"Iteration no. 10"
"Thread taking care of 9"
"Thread taking care of 10"
mt.rb:21:in `join': deadlock detected (fatal)
    from mt.rb:21:in `block in <main>'
    from mt.rb:21:in `each'
    from mt.rb:21:in `<main>'

我做错了什么,在这里?我已经尝试了很多东西,调用Thread#join而不是Thread#stop,在我完成时根本不调用任何Thread方法等等。

提前致谢!


修订代码:

require 'thread'

ary = *0..10 

res = 0
mutex = Mutex.new

ary.each do |x|
    p "Iteration no. #{x}"
    t = Thread.new do
        p "Thread taking care of #{x}"
        mutex.synchronize do
            res += x
        end
        t.stop
    end
end

Thread.list.each &:join
puts res

4 个答案:

答案 0 :(得分:3)

在持有互斥锁时,不要stop一个线程。 stop方法将当前线程置于休眠状态并调度其他线程。现在,第一个线程正在持有互斥锁,因此无论其他线程如何安排,最后都会等待停止的线程释放永远不会发生的互斥锁。死锁。

答案 1 :(得分:0)

@ FranciscoP.w你在循环中定义的东西仍然是循环的本地,你已经在循环中调用了它在循环外部不可用的线程,我认为你应该在循环外定义一个变量并将该线程传递给变量,然后在循环完成时线程将可用。

e.g:

threads = []

threads << Thread.new do
ary.each do |x|
    p "Iteration no. #{x}"
        mutex.synchronize do
            res += x
        end
end
threads.each { |t| t.join }

答案 2 :(得分:0)

您不能在线程内部使用变量t。尝试使用Thread.stop,指示当前线程。如:

require 'thread'

ary = *0..10 

res = 0
mutex = Mutex.new

ary.each do |x|
    p "Iteration no. #{x}"
    t = Thread.new do
        p "Thread taking care of #{x}"
        mutex.synchronize do
            res += x
        end
        Thread.stop
    end
end

Thread.list.each &:join
puts res

此外,我不知道您是否能够加入已停止的线程。为什么不在加入之前重新激活呢?

Thread.list.each {|t| t.run; t.join }
puts res

答案 3 :(得分:0)

你不能做Thread.list.join,因为这个列表包含主线程。

如果你做了Thread.main.join,它会引发错误,因为你在等待自己,这是无稽之谈。

你可以这样做:

Thread.list.delete_if { |t| t == Thread.main }.map(&:join)