在程序启动时,我调用以下函数来初始化解释器:
void initPython(){
PyEval_InitThreads();
Py_Initialize();
PyEval_ReleaseLock();
}
每个线程都创建自己的数据结构并通过以下方式获取锁定:
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
//call python API, process results
PyGILState_Release(gstate);
一旦你理解了GIL就更直接了,但问题是我在调用Py_Finalize()时遇到了段错误。
void exitPython(){
PyEval_AcquireLock();
Py_Finalize();
}
这个引用对于Py_Finalize()是相当可疑的(或者我只是以错误的方式读取它)而且我不确定PyEval_AcquireLock()是否可以在有一些活动线程的情况下获取锁定,如果有的话会发生什么调用Py_Finalize()时是活动线程。
无论如何,即使我确定所有线程都完成了他们的工作,但是只有在创建了至少一个线程的情况下才会出现段错误。例如。从exitPython()后面调用initPython()不会产生错误。
我可以忽略这个问题并希望操作系统知道它的作用,但我会优先考虑是否可以弄清楚发生了什么......
答案 0 :(得分:7)
是的,整个部分相当可疑,但我认为我犯了错误。
我必须在初始化解释器时保存PyThreadState并在我完成时交换此状态(不知道为什么我需要一个特定的ThreadState来调用Finalize - 不应该每个状态都工作吗?)
无论如何,如果其他人遇到同样的问题就是这个例子:
PyThreadState *mainstate;
void initPython(){
PyEval_InitThreads();
Py_Initialize();
mainstate = PyThreadState_Swap(NULL);
PyEval_ReleaseLock();
}
void exitPython(){
PyEval_AcquireLock();
PyThreadState_Swap(mainstate);
Py_Finalize();
}
唯一的问题是,即使仍有线程工作,我也可以像其他所有线程一样获取锁。 API没有提到当其他线程仍在工作时调用Finalize()时会发生什么。听起来像是竞争条件的完美例子。
答案 1 :(得分:1)
您是否尝试过评论线程中完成的所有“工作”?用繁忙的循环或睡眠或其他东西替换它。这将有助于确定它是您的初始化/关闭代码,还是您实际在Python之间做的事情。也许您没有正确设置线程 - C API中有许多特定于线程的函数,我不确定您需要哪些函数来确保正常运行。
答案 2 :(得分:1)
通过嵌入式解释器从不同的线程运行包含pyxhook
的脚本时,我也遇到了类似的问题。
如果一次运行一个脚本,则没有问题。钩子被正确释放但如果两个或多个脚本并行运行,则挂钩不会停止。虽然我的脚本正确返回并且cancel()
中的pyxhook
也正常返回,但我认为仍有一些线程正在运行与xlib
相关。这个pyxhook
问题我通过保留一个全局标记来解决,如果pyxhook
已经在运行,而不是从每个线程重新初始化pyxhook
。
现在关于Py_Finalize()
,如果在每个帖子中重新初始化pyxhook
:
如果我在调用PyEval_AcquireLock()
之前没有调用PyThreadState_Swap()
和Py_Finalize()
,则它会在Linux中终止但不会在Win32中终止。如果我没有通过PyEval_AcquireLock()
和PyThreadState_Swap()
,那么在Win32中会出现问题。
暂时我的临时解决方案是在两个不同的操作系统中以不同方式终止。