2014-01-22 12 views
0

我寫了接受來自使用RtMidi庫中的MIDI設備MIDI輸入一個小模塊: http://www.music.mcgill.ca/~gary/rtmidi/問題運行導出的C++函數在單獨的線程在Python

我使用的庫沒有任何問題,它的偉大工程。我使用Cython導出了我的模塊以供Python使用。該模塊導入正確並且可以與Python正確地協作。問題在於,由於這會無限期地等待用戶MIDI輸入,因此有必要在其自己的線程中產生該輸入。

我已經測試了在C++中使用std :: thread在自己的線程中產生這個,它工作得很好。問題是在使用導出的庫時特別試圖從Python內部自行創建它。

下面的代碼:

import midi #my exported C++ module 
    import threading 
    import time 

    def test(): 
     for i in range(0, 10): 
     print(i) 
     time.sleep(.25) 

    my_thread = threading.Thread(target=test) 
    my_thread.daemon = False 
    my_thread.start() 

    midi_input = midi.MidiListen() 
    midi_input.start() #listen for MIDI input indefinitely 

什麼捲起發生的事情是,我已經催生了線程將打印「0」,然後將MIDI輸入讀者會開始,第一個線程將無法繼續打印直到midi_input.start()函數返回,而不是同時運行這兩個函數。

此外,我試過這段代碼運行在midi_input.start()是在一個單獨的線程,而不是測試()函數執行的其他方式。

我在這裏做錯了什麼?

編輯: 謝謝傑夫的回答,我能解決我的問題。

通知了「nogil」和「吉爾」的函數聲明的末尾。

這是我的.pyx文件:

from libcpp.vector cimport vector 

cdef extern from "hello_midi.h": 
    cdef cppclass MidiInput: 
     void mycallback(double deltatime, vector[unsigned char]* message, void* userData) with gil 
     int midi_listen() nogil 

cdef void midi_init(MidiInput* ob): 
    with nogil: 
     ob.midi_listen() 

cdef class MidiListen: 
cdef MidiInput* thisptr 
def __cinit__(self): 
    self.thisptr = new MidiInput() 
def start_midi(self): 
    midi_init(self.thisptr) 

這裏是最終的Python腳本:

import midi 
import threading 
import time 


def test(): 
    for i in range(0, 10): 
     print(i) 
     time.sleep(.25) 

def start(): 
    x = midi.MidiListen() 
    x.start_midi() 

thread = threading.Thread(target=start) 
thread.start() 

test() 
+0

考慮的Python看'multiprocessing'模塊,或者閱讀有關全局解釋器鎖(GIL)。 –

回答

3

這是因爲Python的全局解釋鎖(GIL)的。一次只允許一個線程運行Python解釋器。要解決你的問題,你應該調用到RtMidi之前釋放GIL。 Cython手冊在Acquiring and Releasing the GIL部分討論了這個問題。

您的新代碼將看起來像

def start(self): 
    with nogil: 
     # Call rtmidi functions 

但是,如果你要處理任何Python對象,你必須獲得GIL,例如在回調中。它看起來像RtMidi的回調面向因此,如果您目前有

cdef void callback(...): 
    # Code that posts the midi event to python somehow 

您應將其更改爲

cdef void callback(...) with gil: 
    # The same code as before 

這將導致用Cython發出代碼,獲取GIL運行函數體前鎖定回來。

相關問題