代码之家  ›  专栏  ›  技术社区  ›  Bill Dueber

使用sizedqueue的Ruby代码死锁

  •  6
  • Bill Dueber  · 技术社区  · 16 年前

    我想我遇到了一个基本的误解,关于Ruby中线程是如何工作的,我希望能得到一些见解。

    我想要一个简单的生产者和消费者。首先,一个生产者线程,它从一个文件中提取行,并将它们粘贴到一个大小合适的队列中;当这些行用完时,在末尾粘贴一些令牌,让消费者知道事情已经完成。

    require 'thread'
    numthreads = 2
    filename = 'edition-2009-09-11.txt'
    
    bq = SizedQueue.new(4)
    producerthread = Thread.new(bq) do |queue|
      File.open(filename) do |f|
        f.each  do |r|
          queue << r
        end
      end
      numthreads.times do
        queue << :end_of_producer
      end
    end
    

    现在有几个消费者。为了简单起见,让他们什么也不做。

    consumerthreads = []
    
    numthreads.times do
      consumerthreads << Thread.new(bq) do |queue|
        until (line = queue.pop) === :end_of_producer
           # do stuff in here
        end
      end
    end
    
    producerthread.join
    consumerthreads.each {|t| t.join}
    
    puts "All done"
    

    我的理解是:(a)一旦sizedqueue满了,生产者线程将阻塞,并最终返回到填充状态;(b)消费者线程将从sizedqueue中拉出,在清空时阻塞,并最终完成。

    但是在ruby1.9(ruby1.9.1p243(2009-07-16版本24175)[i386-darwin9])下,连接上会出现死锁错误。这是怎么回事?我只是不知道线程之间的交互在哪里,除了通过sizedqueue,它应该是线程安全的。

    任何见解都会受到赞赏。

    1 回复  |  直到 16 年前
        1
  •  3
  •   Marc-André Lafortune    16 年前

    您的理解是正确的,并且您的代码在我的机器上工作,在稍微更新的Ruby版本上(Ruby 1.9.2dev(2009-08-30 Trunk 24705)[i386-Darwin10.0.0]和Ruby 1.9.2dev(2009-08-30 Trunk 24705)[i386-Darwin10.0.0])