1 用Python写的程序,由于其GIL的存在,死锁的情况变得有点复杂。
2 基本上可以分成两种情况:
一种是在调用Thread.join,Queue.put,Queue.get,Lock.acquire这些函数造成的死锁,可以归结成Python代码层造成的死锁
另一种情况是由于无法获取GIL而造成的死锁,可以归结成C代码层造成的死锁,具体原因是这样的:
由于某个Python线程调用了一个C函数,而这个函数在等某一资源的释放,并且Python线程在调用这个函数之前又没有把GIL给释放掉,一直占着GIL,
造成其它的Python线程因无法获取GIL都处于死锁状态
因为这时候Python代码已经无法执行,用pydev,winpdb等工具已经无能为力了。
3 前一种情况的死锁比较好查,用pydev,winpdb查看下堆栈就可以分析出死锁的具体位置。
4 由于第一种情况的死锁原因查起来比较简单,这里重点讨论一下第二种情况的死锁问题的查找。
5 按照惯例,照样先举一个例子,这个例子从《Cython进阶--用Cython封装Callback函数》里的示例代码修改而来。
6 改动很小,只是在JoinThread这个函数里去掉了PyEval_SaveThread和PyEval_RestoreThread的调用,用于造成一个死锁的情况。
cdef extern from "pthread.h":
ctypedef void *pthread_t
ctypedef structpthread_attr_t:
pass
int pthread_create(pthread_t *__newthread, \
pthread_attr_t *__attr, \
void *(*__start_routine) (void *) except*, \
void *__arg)
int pthread_join(pthread_t __th, void **__thread_return)
cdef extern from "Python.h":
ctypedef enumPyGILState_STATE:
pass
ctypedef enumPyThreadState:
pass
PyGILState_STATEPyGILState_Ensure()
voidPyGILState_Release(PyGILState_STATE)
PyThreadState *PyEval_SaveThread()
voidPyEval_RestoreThread(PyThreadState *)
void PyEval_InitThreads()
void Py_INCREF(objectobj)
void Py_DECREF(objectobj)
def Callback(obj):
if hasattr(obj,'run'):
obj.run()
cdef void * start (void * param) except*:
cdef PyGILState_STATEstate
cdef object obj =