【问题标题】:Ruby: Concurrent::Semaphore yields deadlockRuby:Concurrent::Semaphore 产生死锁
【发布时间】:2018-09-21 05:11:34
【问题描述】:

我正在测试 Concurrent::Semaphore,

require 'concurrent'

loop do
  semaphore = Concurrent::Semaphore.new(3)

  (1..5).each_with_object([]) do |_n, result|
    result << Thread.new do
      semaphore.acquire

      print '.'

      semaphore.release
    end
  end.each(&:join)
end

但代码在运行几秒钟后会产生如下异常。

./semaphore.rb:14:in `join': No live threads left. Deadlock? (fatal)
2 threads, 2 sleeps current:0x00007f867c9a73a0 main thread:0x00007f867a503350
* #<Thread:0x00007f867a869c20 sleep_forever>
   rb_thread_t:0x00007f867a503350 native:0x00007fffa9b16380 int:0
   ./semaphore.rb:14:in `join'
   ./semaphore.rb:14:in `each'
   ./semaphore.rb:14:in `block in <main>'
   ./semaphore.rb:3:in `loop'
   ./semaphore.rb:3:in `<main>'
* #<Thread:0x00007f867b8891f0@./semaphore.rb:7 sleep_forever>
   rb_thread_t:0x00007f867c9a73a0 native:0x000070000c9b8000 int:0
    depended by: tb_thread_id:0x00007f867a503350
   ./semaphore.rb:10:in `write'
   ./semaphore.rb:10:in `print'
   ./semaphore.rb:10:in `block (3 levels) in <main>'

用法有问题吗?

(使用 MRI ruby​​ 2.5.1p57(2018-03-29 修订版 63029)[x86_64-darwin17])

【问题讨论】:

    标签: ruby deadlock semaphore


    【解决方案1】:

    (明显的)死锁不是由您使用信号量直接引起的。相反,这里发生的是你有两个线程(你都在等待完成),它们都是阻塞的。

    您的第一个线程确实在等待信号量可用。

    但是,第二个线程当前正在将数据写入STDOUT,在您的情况下这也是阻塞的。如果读取 Ruby 进程(例如终端)的STDOUT 的进程不够快,无法读取所有数据,通常会发生这种情况。一旦管道的缓冲区已满,写入STDOUT 会阻塞,从而导致线程也无法运行。

    Thread#join 检测到这会导致抛出异常。

    要解决此问题,您只需确保从进程的STDOUT 中读取的速度足够快。然后,我无法再重现该问题。

    出于文档目的:我可以通过运行 ruby ./semaphore.rb | ruby -e "sleep 30" 和包含问题中显示的代码的 semaphore.rb 来始终重现 OP 描述的问题。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2013-12-28
    • 2013-03-06
    • 2011-05-04
    • 1970-01-01
    • 2020-03-11
    • 2012-05-21
    相关资源
    最近更新 更多