【问题标题】:Ruby Threading Won't Context SwitchRuby 线程不会进行上下文切换
【发布时间】:2011-08-13 22:27:32
【问题描述】:

使用 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 处理线程的方式有关。任何帮助表示赞赏。

【问题讨论】:

    标签: ruby alsa


    【解决方案1】:

    没有 cext,这两个确实并行运行。 GIL 不会让带有 C 扩展名的两个线程同时运行,因为它不知道它是线程安全的。

    【讨论】:

    • 它们本身不需要并行运行,只要它们上下文切换进出,感觉就像它们在并行运行。 ruby 是否正在采取措施防止这种情况发生?
    • 是的。就像我说的,C 扩展意味着 GIL 被具有 c 扩展的线程持有,这意味着其他线程无法运行。
    【解决方案2】:

    您显示的循环将阻塞整个解释器(假设 poll 正在阻塞),就像史蒂夫所说的那样。您需要使用 Ruby (MRI/YARV) C API 中的rb_thread_blocking_region 调用 poll()。

    【讨论】:

      猜你喜欢
      • 2011-07-23
      • 2018-09-22
      • 2017-09-09
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 2016-10-12
      • 1970-01-01
      相关资源
      最近更新 更多