我在python模块中包装属于多线程C框架的C函数。在这个框架中,当某些事件被触发时会执行回调。但是,回调并不总是从同一个线程执行。在
与我的问题相关的回调是在python ctypes中定义的。普通ctypes回调的问题是,它们试图使用pythoncapi获取GIL。当从未调用Py_initialize()
的线程运行时,此获取失败。在
由于框架的原因,我无法更改回调的执行方式,我唯一能做的就是更改回调函数本身。在
为了控制获取GIL的方式,我创建了一个C回调函数,它包装了python回调函数:
void* callback(void*){
if (PyGILState_GetThisThreadState()) {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyRun_SimpleString(...);
PyGILState_Release(gstate);
} else {
PyRun_SimpleString(...);
}
}
如果PyGILState_GetThisThreadState()
函数返回非空值,则表示回调是从调用Py_initialize()
的同一线程执行的。这意味着可以使用pygilstateapi。这工作正常。在
当从其他线程运行回调时,else
部分被执行。如果它是该线程的堆栈上唯一的python调用,它将被正确执行,但是当堆栈中有一个未完成的python调用时,它将导致分段错误:
我也尝试过在else部分使用PyGILState API,但结果却是相反的情况:对于连续的python调用,回调成功,但当它是堆栈中的第一个python调用时,会导致死锁:
#0 0x0000003c8de0da00 in sem_wait () from /lib64/libpthread.so.0
#1 0x0000003c46cfd428 in PyThread_acquire_lock () from /usr/lib64/libpython2.6.so.1.0
#2 0x0000003c46cd7784 in PyEval_RestoreThread () from /usr/lib64/libpython2.6.so.1.0
#3 0x0000003c46cf0f58 in PyGILState_Ensure () from /usr/lib64/libpython2.6.so.1.0
如果我以与if(PyGILState_GetThisThreadState()){..}
部分相同的方式获得GIL状态,使用PyGILState_Ensure
和{
有没有方法可以确定回调是要进行第一个python调用还是一个连续调用?或者是解决这个线程问题的方法?在
显然我可以使用}。在
_PyThreadState_Current
,我仍然不能百分之百确定为什么这样做,但它确实起作用了。似乎应该是currentThread
,而不是{感谢this post为我指明了正确的方向。在
相关问题 更多 >
编程相关推荐