C中多线程python扩展中的Segfault

时间:2010-03-19 16:33:53

标签: python multithreading

我有一个非常精简的例子,它创建了一个我似乎无法摆脱的段错误。 Python脚本在扩展中调用C函数,该函数使用pthreads创建新线程。我在新线程的python调用(PyRun_SimpleString)周围使用PyGILState_Ensure和PyGILState_Release,但也许我没有正确使用它们或者错过了其他一些步骤。注释掉receive_audio函数中的python调用,不再发生段错误。有什么想法吗?

输出:

python lib / test.py
(主线程)initmodule完成
(主线程)调用run_thread()
(主线程)创建线程
(新主题)在receive_audio()中 - 获取GIL
(新线程)python打印!
(新主题)在receive_audio()中 - 释放GIL
(新主题)循环0
分段错误

C代码如下:

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);
    }
}

1 个答案:

答案 0 :(得分:3)

我不肯定这与您的问题有关,但有一件看起来可疑的事情是模块初始化函数中的PyEval_ReleaseLock()调用。我怀疑Python期望你的模块初始化程序从它下面释放出GIL,并且快速查看一些示例代码here并没有显示出这些内容。您可以尝试删除PyEval_ReleaseLock()调用并告诉我们会发生什么吗?

顺便说一句,我同意run_thread()中的PyGILState _ *()调用应该没有效果;你应该能够删除它们。