从C调用Py_Finalize()

时间:2009-09-15 12:51:46

标签: c++ python c

这是Call Python from C++

的后续行动

在程序启动时,我调用以下函数来初始化解释器:

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()不会产生错误。

我可以忽略这个问题并希望操作系统知道它的作用,但我会优先考虑是否可以弄清楚发生了什么......

3 个答案:

答案 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中会出现问题。

暂时我的临时解决方案是在两个不同的操作系统中以不同方式终止。