C中多线程python扩展中的Segfault
我有一个非常精简的示例,它创建了一个我似乎无法摆脱的segfault。Python脚本在扩展中调用一个C函数,该扩展使用pthreads创建一个新线程。我在新线程中使用PyGILState_sure和PyGILState_Release来处理python调用(PyRun_SimpleString),但可能我没有正确使用它们,或者错过了其他步骤。注释掉receive_audio函数中的python调用后,segfault不再发生。有什么想法吗 输出: python库/test.pyC中多线程python扩展中的Segfault,python,multithreading,Python,Multithreading,我有一个非常精简的示例,它创建了一个我似乎无法摆脱的segfault。Python脚本在扩展中调用一个C函数,该扩展使用pthreads创建一个新线程。我在新线程中使用PyGILState_sure和PyGILState_Release来处理python调用(PyRun_SimpleString),但可能我没有正确使用它们,或者错过了其他步骤。注释掉receive_audio函数中的python调用后,segfault不再发生。有什么想法吗 输出: python库/test.py (主线程)初始
(主线程)初始化模块完成
(主线程)调用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);
}
}
PyMODINIT_FUNC streamaudio(){
PyObject*m=Py_InitModule(“streamaudio”,方法);
PyEval_InitThreads();
mainThreadState=PyThreadState_Get();
PyEval_ReleaseLock();
printf(“(主线程)initmodule complete\n”);
}
静态PyObject*运行线程(PyObject*self,PyObject*args)
{
int ok,流的id;
皮吉州;
gstate=PyGILState_sure();
ok=PyArg\u语法元组(args,“i”和流\u id);
PyRun_SimpleString(“打印(主线程)创建线程”\n”);
int rc=pthread_create(&thread,NULL,receive_audio,(void*)stream_id);
PyRun_SimpleString(“打印(主线程)线程已创建”\n”);
Pygilu状态释放(gstate);
返回Py_BuildValue(“i”,rc);
}
void*接收音频(void*x)
{
printf(“(新线程)在receive_audio()-获取GIL\n”);
皮吉州;
gstate=PyGILState_sure();
PyRun_SimpleString(“打印”(新线程)python打印!”\n);
Pygilu状态释放(gstate);
printf(“(新线程)在receive_audio()-released GIL\n”中);
int i;
对于(i=0;i<100;i++){
printf(“(新线程)循环%d\n”,i);
睡眠(1);
}
}
我不确定这是否与您的问题相关,但有一件看起来可疑的事情是模块初始值设定项函数中的PyEval_ReleaseLock()调用。我怀疑Python是否期望您的模块初始值设定项将GIL从其下面释放出来,而快速查看一些示例代码并没有显示出这方面的任何内容。能否尝试删除PyEval_ReleaseLock()调用并告诉我们发生了什么
顺便说一句,我同意run_thread()中的PyGILState_*()调用应该没有效果;您应该能够删除它们。注意,围绕pthread_create函数的PyGILState_sure()和PyGILState_Release调用似乎无关紧要。我认为这是意料之中的,因为它是由主线程运行的。很好!成功了。我从这里开始编写代码:他的示例是在C中嵌入python,而我做的是相反的,所以这个调用是灾难性的。谢谢