2011-04-27 76 views
2

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

回答

2

没有cext,那两个确实以并行方式运行。 GIL不会让两个线程一起运行C扩展,因为它不知道它是线程安全的。

+0

它们不需要并行运行,只要它们上下文切换,以便它感觉像是在并行运行。红宝石正在做些什么来防止这种情况发生? – 2011-04-27 15:40:23

+1

是的。就像我说的那样,C扩展意味着GIL被带有c扩展名的线程持有,这意味着其他线程不能运行。 – 2011-04-27 15:43:25

3

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