2015-01-04 5 views
4

Я изучаю Ruby в течение последних нескольких дней, и у меня возникли некоторые проблемы, связанные с реализацией потоков. Я программировал на других языках раньше (в основном, Java и C), и я все еще не мог понять, в чем проблема. Я запускаю ruby ​​2.1.2p95 на сервере Ubuntu 14.10. Код в вопросе от Humble Литл Рубин книги г-соседски в:Вводная версия Ruby Threading

mate = Thread.new do 
    puts "Ahoy! Can I be dropping the anchor sir?" 
    Thread.stop 
    puts "Aye sir, dropping anchor!" 
end 

Thread.pass 

puts "CAPTAIN: Aye, laddy!" 

mate.run 
mate.join 

вывод должен быть:

Ahoy! Can I be dropping the anchor sir? 
CAPTAIN: Aye, laddy! 
Aye sir, dropping anchor! 

Но вместо этого, я получаю следующий присоединиться и тупиковое ошибку:

CAPTAIN: Aye, laddy! 
Ahoy! Can I be dropping the anchor sir? 
ex2.rb:12:in `join': No live threads left. Deadlock? (fatal) 
    from ex2.rb:12:in `<main>' 

Я столкнулся с ошибками с другими примерами потоков из других ресурсов и попытался запустить примеры на других машинах Ubuntu, а также попробовать Ruby 2.2. Есть ли вопиющая концепция, которую я пропускаю? Что-то изменилось в недавних версиях Ruby, которые сочли бы примеры устаревшими? Спасибо за помощь!

+0

Ваш код работает как ожидается для меня, используя Ruby 2.0.0 на OS X Yosemite. – pjs

+0

Я использую ruby ​​2.2.0 на OS X Yosemite, и я получаю сообщение об ошибке. Я предполагаю, что это ошибка. – Adrian

+0

Я обнаружил, что этот код вызывает ошибку для меня более надежно: 'Thread.new {Thread.stop} .join' – Adrian

ответ

2

Has something changed in recent revisions of Ruby that would deem the examples out-of-date?

Да. Похоже, эта книга была written for Ruby 1.8, которая использовала green threads. Ruby 1.9 использует родной потоков (где потоки запланированы ОС).

Сравните документацию для Thread.pass method in Ruby 1.8.7:

Invokes the thread scheduler to pass execution to another thread.

В Ruby 2.1.2 (версия, которую вы используете), this methods documentation выглядит следующим образом:

Give the thread scheduler a hint to pass execution to another thread. A running thread may or may not switch, it depends on OS and processor.

Таким образом, в текущих версиях планирования является не детерминированным в том, как это было в Ruby 1.8.7, ОС может игнорировать вызов Thread.pass и сначала запустить основной поток, что вызывает проблемы.

Запуск этого сценария на моей машине (Mac OS 10.9, Ruby 2.2.0) я получаю как результат, иногда это работает, и я вижу:

Ahoy! Can I be dropping the anchor sir? 
CAPTAIN: Aye, laddy! 
Aye sir, dropping anchor! 

Другие времена он терпит неудачу с:

CAPTAIN: Aye, laddy! 
Ahoy! Can I be dropping the anchor sir? 
capt-thread.rb:12:in `join': No live threads left. Deadlock? (fatal) 
    from capt-thread.rb:12:in `<main>' 
+0

Эта ошибка все еще меня смущает, потому что даже если' Thread.pass' не имеет эффект, по-прежнему не тупик, не так ли? Я ожидал бы просто увидеть результат в неправильном порядке. – Adrian

+0

@Adrian Ошибка возникает из-за того, что вы пытаетесь «присоединиться» (это ждать ее завершения), поток, который был остановлен. Он никогда не может закончиться, и Ruby обнаруживает это и вызывает исключение. Я думаю, что «Тупик?» В сообщении об ошибке - это просто предположение о том, что могло произойти. В этом случае это не тупик, но немного похоже на то, что поток 'mate' ждет основного потока, чтобы запустить его, и основной поток считает, что он уже имеет. – matt

+0

Я согласен с @Adrian. Я чувствую, что даже если Thread.pass не заставляет основной поток передавать время выполнения другому потоку, использование Thread.join, по крайней мере, позволит всем потокам завершить выполнение. Редактировать: Просто увидев ваш ответ на Адриана, позвольте мне немного поиграть с примером. – Connor

Смежные вопросы