Ruby线程不会上下文切换

问题描述

| 使用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音序器并等待其上的输入事件。本质上,我希望我的代码不断输出“在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处理线程的方式有关。任何帮助表示赞赏。     

解决方法

您显示的循环会像Steve所说的那样阻塞整个解释器(假设
poll
被阻塞)。您需要使用Ruby(MRI / YARV)C API中的rb_thread_blocking_region调用poll()。     ,没有cext,这两个确实可以并行运行。 GIL不允许使用C扩展名同时运行两个线程,因为它不知道它是线程安全的。