2014-02-25 6 views
1

MIDI 입력을 기다리고 이에 응답하는 GTK/GStreamer 응용 프로그램 (오디오 용 Cgstreamer 및 GUI 용 pygobject gtk)을 만듭니다. MIDI 캡처는 RTMidi 라이브러리로 처리됩니다. 콜백 기반 C 라이브러리를 사용할 때 Cython으로 GIL을 해제 할 수 없습니다.

는 과거에 나는 성공적으로 내 사이 썬 .pyx 파일에 길과 키워드를 nogil 및 를 사용하여 GIL을 해제 할 수 있었다. 문제는 Python의 C 콜백 함수에서 MIDI 입력 값을 읽을 수 있어야하므로이 입력을 기반으로 GUI를 변경할 수 있습니다.

나는 파이썬 코드가 python 함수 객체 (내 RTMidi C 콜백에서 호출 할 함수)를 전달하도록 코드를 약간 재구성했습니다. 그런 다음 Cython을 사용하여 유형 객체에 캐스트합니다. void * 그래서이 데이터를 C 코드를 통해 전달할 수 있습니다.

즉, MIDI 입력이 감지 될 때마다 void *로 전달 된 python 함수가 호출됩니다. 이것은 잘 작동합니다. 이 기능을 추가 한 이후로 작동하지 않는 부분은 GIL을 해제하는 것입니다. 이제 응용 프로그램이 시작될 때마다 MIDI 입력을 받아들이는 함수가 자체 스레드에서 제대로 시작되지 않으므로 GTK GUI는 실제로 표시되지 않습니다.

사이 썬의 문서에 GIL 해제에 대한 몇 가지 정보 : 어떤 방법으로 파이썬 객체를 조작해서는 안 명령문의 몸에

코드를 먼저없이 파이썬 객체를 조작 아무것도 전화를 안 재 - 획득 GIL. Cython은 현재 이것을 확인하지 않습니다.

나는 이러한 규칙을 위반하고 있다고 생각하지 않습니다.

Cython의 버그 일 수 있습니까? 아니면 여기에 누락 된 것이 있습니까?

다른 사람이 Cython을 사용하여 C 콜백에서 파이썬 기능을 호출 한 경험이 있습니까?

여기에는 .pyx의 축소판이 있습니다. 참고와 GIL을 해제하고 얻기 위해 사용 "nogil"키워드 "길에"

from libcpp.vector cimport vector 

cdef extern from "player.h": 
    cdef cppclass Player: 
     Player() 
     void listen(void(*)(double, vector[unsigned char]*, void*), void* userdata) nogil 

cdef extern from "midi.h": 
    cdef cppclass MidiInput: 
     int midi_listen(void(*)(double, vector[unsigned char]*, void*), void* userdata) nogil 

cdef void midi_init(Player* ob, void* function): 
    with nogil: 
     ob.listen(callback, function) 

#helper function which the RTMidi callback is set to 
#the python function is called from the callback 
cdef void callback(double deltatime, vector[unsigned char]* message, void* userdata) with gil: 
    (<object>userdata)()  

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

cdef class PyPlayer: 
    cdef Player *thisptr 
    def __cinit__(self): 
     self.thisptr = new Player() 
    def get_midi_in(self, f): 
     midi_init(self.thisptr, <void*>f) 

여기에 pygobject의 GTK가있다 :

#!/usr/bin/python 
from gi.repository import Gtk 
import player 
import threading 

class MyWindow(Gtk.Window): 
    def __init__(self): 
     Gtk.Window.__init__(self, title="Hello World") 
     self.player = player.PyPlayer() 


def test(): 
    print("hello, world!") 

win = MyWindow() 

#this way of starting the midi on a separate thread worked before, 
#but not anymore 
thread = threading.Thread(target=win.player.get_midi_in(test)) 
thread.daemon = True 
thread.start() 

win.connect("delete-event", win.close_app) 
win.show_all() 
Gtk.main() 

답변

1

내가 전에이 캐치하지 않았는지 확실하지. 당신이 스레드에 매개 변수로 함수 개체를 전달하려는 경우, 그냥 함수 객체를 전달 코드 줄에서 함수를 호출하지되기 전에 ...과 같이

thread = threading.Thread(target=win.player.get_midi_in, args=(test,)) 

을 해.