#ruby #alsa
#ruby #alsa
Вопрос:
Используя MRI ruby 1.9, у меня есть некоторый код, подобный
def foo()
puts "in foo"
loop do
puts "in foo loop"
end
end
def bar()
puts "in bar"
start_alsa_listener
end
foo_thread = Thread.new { foo }
bar_thread = Thread.new { bar }
foo_thread.join
bar_thread.join
start_alsa_listener — это блокирующий вызов библиотеки, который открывает ALSA midi sequencer и ожидает событий ввода в нем. По сути, я хочу, чтобы мой код постоянно выводился «в цикле foo» и в то же время мог получать события ALSA midi и также выводить их на консоль (что start_alsa_listener и делает, когда получает событие).
Проблема в том, что когда я запускаю приведенный выше код, как только bar () запускает его, контекст никогда не переключается обратно на foo ().
start_alsa_listener — это расширение ruby C, которое выглядит как:
for(;;) {
poll(/* args */); /* wait for input data */
/* print data to console */
}
Возможно, это связано с чем-то в Ruby, что я делаю неправильно с потоковой обработкой, или, может быть, что-то связано с опросом, или, может быть, что-то связано с тем, как ALSA обрабатывает потоки. Приветствуется любая помощь.
Ответ №1:
Показанный вами цикл заблокирует весь интерпретатор (при условии, что poll
он блокируется), как сказал Стив. Вам нужно вызвать poll(), используя rb_thread_blocking_region из Ruby (MRI / YARV) C API.
Ответ №2:
Без cext эти два работают параллельно. GIL не позволяет запускать два потока одновременно с расширением C, потому что он не может знать, что это потокобезопасно.
Комментарии:
1. им не нужно работать параллельно как таковым, если они включают и выключают контекст, чтобы создавалось впечатление, что они работают параллельно. Делает ли ruby что-нибудь, чтобы предотвратить даже это?
2. ДА. Как я уже сказал, расширение C означает, что GIL удерживается потоком с расширением c, что означает, что другие потоки не могут запускаться.