Ruby: Concurrent :: Семафор выходит из тупика - PullRequest
0 голосов
/ 21 сентября 2018

Я тестирую 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 (версия 20130-03-29 63029) [x86_64-darwin17])

1 Ответ

0 голосов
/ 21 сентября 2018

(Очевидная) тупиковая ситуация не связана напрямую с использованием семафоров.Вместо этого, здесь происходит то, что у вас есть два потока (оба из которых вы ожидаете до конца), которые оба блокируют.

Ваш первый поток действительно ожидает, чтобы семафор был доступен.

Однако второй поток в настоящее время записывает данные в STDOUT, который в вашем случае также блокирует.Обычно это может произойти, если процесс, считывающий STDOUT вашего процесса Ruby (например, вашего терминала), не достаточно быстр, чтобы прочитать все данные.Когда буфер канала заполнен, выполняется запись в STDOUT блоков, в результате чего поток также не может быть активным.

Это обнаруживается Thread#join, что приводит к возникновению исключения.

Чтобы решить эту проблему, вы можете просто убедиться, что вы читаете достаточно быстро из STDOUT вашего процесса.Тогда я больше не мог воспроизводить проблему.

Для целей документации: я мог последовательно воспроизвести проблему, описанную OP, запустив ruby ./semaphore.rb | ruby -e "sleep 30" с semaphore.rb, содержащей код, показанный в вопросе.

...