2011-04-27 80 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()。