2010-03-19 10 views
4

J'ai un exemple très réduit qui crée une erreur de segmentation dont je n'arrive pas à me débarrasser. Le script Python appelle une fonction C dans une extension, ce qui crée un nouveau thread à l'aide de pthreads. J'utilise PyGILState_Ensure et PyGILState_Release autour de mon appel python (PyRun_SimpleString) dans le nouveau thread, mais peut-être que je ne les utilise pas correctement ou que j'ai manqué une autre étape. Commenter les appels python dans la fonction receive_audio, la segfault ne se produit plus. Des idées?Segfault en extension python multithread en C

Sortie:

python lib/test.py
(thread principal) InitModule complet
(thread principal) Appel run_thread()
(thread principal) Création fil
(Nouveau fil) En receive_audio() - acquisition de GIL
(Nouveau sujet) python print!
(Nouveau fil) Dans receive_audio() - publié GIL
(Nouveau fil) Looping 0
Segmentation fault

code C comme suit:

PyMODINIT_FUNC streamaudio() { 
    PyObject *m = Py_InitModule("streamaudio", methods); 
    PyEval_InitThreads(); 
    mainThreadState = PyThreadState_Get(); 
    PyEval_ReleaseLock(); 
    printf("(Main Thread) initmodule complete\n"); 
} 

static PyObject* run_thread(PyObject* self, PyObject* args) 
{ 
    int ok, stream_id; 
    PyGILState_STATE gstate; 
    gstate = PyGILState_Ensure(); 
    ok = PyArg_ParseTuple(args, "i", &stream_id); 
    PyRun_SimpleString("print '(Main Thread) Creating thread'\n"); 
    int rc = pthread_create(&thread, NULL, receive_audio, (void*)stream_id); 
    PyRun_SimpleString("print '(Main Thread) Thread created'\n"); 
    PyGILState_Release(gstate); 
    return Py_BuildValue("i", rc); 
} 

void* receive_audio(void *x) 
{ 
    printf("(New Thread) In receive_audio() - acquiring GIL\n"); 
    PyGILState_STATE gstate; 
    gstate = PyGILState_Ensure(); 
    PyRun_SimpleString("print '(New Thread) python print!'\n"); 
    PyGILState_Release(gstate); 
    printf("(New Thread) In receive_audio() - released GIL\n"); 
    int i; 
    for (i = 0; i < 100; i++) { 
    printf("(New Thread) Looping %d\n", i); 
    sleep(1); 
    } 
} 
+0

Une note - les appels PyGILState_Ensure() et PyGILState_Release autour de la fonction pthread_create semblent être sans conséquence. Je pense que c'est normal car il est géré par le thread principal. – cursemyziti

Répondre

3

Je ne suis pas positif que ce sera est pertinent pour votre question, mais une chose qui semble suspecte est l'appel PyEval_ReleaseLock() dans la fonction d'initialisation de votre module. Je doute que Python s'attend à ce que votre initialiseur de module libère le GIL de dessous, et un rapide coup d'œil à un exemple de code here ne montre rien de ce genre. Pourriez-vous essayer de supprimer cet appel PyEval_ReleaseLock() et nous dire ce qui se passe? Par ailleurs, je suis d'accord que les appels PyGILState _ *() dans run_thread() ne devraient avoir aucun effet; vous devriez pouvoir les enlever.

+2

Nice! C'est ce qu'il a fait. Je suivais le code d'ici: http://www.linuxjournal.com/article/3641?page=0,2 Son exemple est pour l'intégration de python dans C, alors que je fais l'inverse, de sorte que l'appel est catastrophique. Merci! – cursemyziti