Boost python/从线程导入模块需要ReleaseLock().为什么

Boost python / importing module from thread requires ReleaseLock(). Why?

本文关键字:ReleaseLock 为什么 模块 python 线程 导入 Boost      更新时间:2023-10-16

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

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

PyEval_InitThreads();

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

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

Py_Initialize();

PyGILState_STATE gstate=PyGILSState_Ensure();

然后我在newThread():中调用一个名为hoge()的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()为什么失败?我不知道。请告诉我如何解决这个问题。



-编辑12/12/28---

我用下面的方法解决了这个问题。

main()中,我执行

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

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

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

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

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

现在,用GIL请求(或"确保")和发布函数调用包装代码并不能解决所有问题——您仍然需要确保,当您有两个线程时,两个都可以访问GIL。如果你没有在主线程上发布GIL,那么你的第二个真正做python的线程将永远被阻止!你试过了吗?如果没有,你可以看看会发生什么。

正确的解决方案——你自己找到的解决方案,是在每个线程上获取并释放GIL,并确保你不会陷入其中一个具有GIL的线程中,而其他线程则处于饥饿状态。