我开发了一个带多线程的boost.python C / C ++程序。
在main()
中,我创建了一个帖子:
PyEval_InitThreads();
pthread_create(& id,& detached_attr,newThread,NULL);
·在newThread()中,我调用了两个Py_ *函数。
Py_Initialize();
PyGILState_STATE gstate = PyGILState_Ensure();
然后我在hoge()
中调用名为newThread()
的C ++函数:
void hoge(){
py::object main_module;
py::object main_namespace;
try {
main_module = py::import("__main__"); //segmentation fault
main_namespace = main_module.attr("__dict__");
} catch (py::error_already_set const &) {
PyErr_Print();
}
//Some boost python code
}
gdb返回跟踪输出在这里。
(gdb) bt
#0 0x4032fe24 in __ctype_b_loc () from /lib/libc.so.6
#1 0x4032fde8 in __ctype_b_loc () from /lib/libc.so.6
为什么import()
会失败?我不知道。请告诉我如何解决这个问题。
--edit 12/12/28 ---
我使用以下方法解决了这个问题。
在main()
中,我执行
Py_Initialize();
PyEval_InitThreads();
PyEval_ReleaseLock();
然后我创建新线程。在新线程中,我执行
PyGILState_STATE gstate = PyGILState_Ensure();
CALL SOME PYTHON CODE
PyGILState_Release(gstate);
但我不知道为什么现在有效。有人可以告诉我原因吗?
答案 0 :(得分:0)
Python,与许多其他解释语言一样,通过利用全局解释器锁(或GIL)来实现线程安全性(see this wiki),这可以阻止两个python解释器调用并行运行。因此,您发出的任何python调用应首先请求锁定,执行命令然后释放锁定。您必须遵循该规则,否则您可能会崩溃解释器,就像您在示例中所做的那样。请注意,您的函数hoge()
未请求GIL,因此崩溃。
现在,使用GIL请求(或“确保”)包装代码并释放函数调用并不能解决所有问题 - 当您有2个线程时,您仍然需要确保两者将有权访问GIL。如果您不在主线程上发布GIL,那么实际执行python内容的第二个线程将永远被阻止!你试过吗?如果没有,你可以看看会发生什么。
正确的解决方案 - 您自己找到的解决方案是在每个线程上获取并释放GIL,并确保您不会卡在其中一个具有GIL的线程中,而其他线程也会陷入困境。