从线程中提升python /导入模块需要ReleaseLock()。为什么?

时间:2012-10-02 08:09:02

标签: c++ c boost-python

我开发了一个带多线程的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);

但我不知道为什么现在有效。有人可以告诉我原因吗?

1 个答案:

答案 0 :(得分:0)

Python,与许多其他解释语言一样,通过利用全局解释器锁(或GIL)来实现线程安全性(see this wiki),这可以阻止两个python解释器调用并行运行。因此,您发出的任何python调用应首先请求锁定,执行命令然后释放锁定。您必须遵循该规则,否则您可能会崩溃解释器,就像您在示例中所做的那样。请注意,您的函数hoge()未请求GIL,因此崩溃。

现在,使用GIL请求(或“确保”)包装代码并释放函数调用并不能解决所有问题 - 当您有2个线程时,您仍然需要确保两者将有权访问GIL。如果您不在主线程上发布GIL,那么实际执行python内容的第二个线程将永远被阻止!你试过吗?如果没有,你可以看看会发生什么。

正确的解决方案 - 您自己找到的解决方案是在每个线程上获取并释放GIL,并确保您不会卡在其中一个具有GIL的线程中,而其他线程也会陷入困境。