1

我开发了一个带有多线程的 boost.python C/C++ 程序。

main()中,我创建了一个线程:

PyEval_InitThreads();

pthread_create( &id, &detached_attr, newThread, NULL );

・在 newThread() 中,我调用了两个 Py_* 函数。

Py_Initialize();

PyGILState_STATE gstate = PyGILState_Ensure();

然后我调用一个名为hoge()in的 C++ 函数newThread()

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()失败?我不知道。请告诉我如何解决这个问题。



——编辑 28 年 12 月 12 日——

我使用以下方法解决了这个问题。

main()中,我执行

Py_Initialize();
PyEval_InitThreads();
PyEval_ReleaseLock();

然后我创建新线程。在新线程中,我执行

PyGILState_STATE gstate = PyGILState_Ensure();
CALL SOME PYTHON CODE
PyGILState_Release(gstate);

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

4

1 回答 1

0

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

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

正确的解决方案 - 您自己找到的解决方案是在每个线程中获取和释放 GIL,并确保您不会陷入其中一个拥有 GIL 的线程而其他线程挨饿。

于 2013-02-08T14:09:50.717 回答