这个问题
pybind11是否神奇地完成了PyGILState_Ensure()
和PyGILState_Release()
的工作?如果没有,我该怎么做?
更多详细信息
关于使用pybind11将python函数作为回调传递给C++的问题,但我还没有找到一个可以解释GIL与pybind11一起使用的问题.
documentation人对GIL非常清楚:
[...] 然而,当线程是从C创建的(例如由具有自己的线程管理的第三方库创建)时,它们不持有GIL,也没有线程状态 struct .
如果需要从这些线程调用Python代码(通常这是上述第三方库提供的回调API的一部分),则必须首先通过创建线程状态数据 struct 向解释器注册这些线程,然后获取GIL,最后存储其线程状态指针,然后才能开始使用Python/C API.
我可以轻松绑定接受回调的C++函数:
py::class_<SomeApi> some_api(m, "SomeApi");
some_api
.def(py::init<>())
.def("mode", &SomeApi::subscribe_mode, "Subscribe to 'mode' updates.");
With the corresponding C++ function being something like:
void subscribe_mode(const std::function<void(Mode mode)>& mode_callback);
但是由于pybind11不知道我的C++实现中发生的线程,我想它不能为我处理GIL.因此,如果mode_callback
由C++创建的线程调用,这是否意味着我应该为SomeApi::subscribe_mode
编写一个包装器,每个调用使用PyGILState_Ensure()
和PyGILState_Release()
?
This answer似乎在做类似的事情,但仍然略有不同:在调用回调时,它似乎不是"接受GIL",而是在启动/停止线程时"释放GIL".我仍然想知道是否有像py::call_guard<py::gil_scoped_acquire>()
这样的东西可以完全满足我(相信我)的需要,即用PyGILState_Ensure()
和PyGILState_Release()
包装我的回调.