假设我通过Boost.Python将c ++ worker类导出到python。工作人员将在不同的线程中处理任务。完成后,工作人员将通过回调通知python调用者。
这是一段示例c ++代码:
class Worker
{
public:
void run()
{
_thread = std::thread( [=] () {
//Initialize and acquire the global interpreter lock
PyEval_InitThreads();
//Ensure that the current thread is ready to call the Python C API
PyGILState_STATE state = PyGILState_Ensure();
//invoke the python function
boost::python::call<void>(this->_callback);
//release the global interpreter lock so other threads can resume execution
PyGILState_Release(state);
});
}
void setPyCallback(PyObject * callable) { _callback = callable; }
private:
std::thread _thread;
PyObject * _callback;
};
现在我在脚本文件test.py中有python代码:
$ cat test.py
import time
import worker
def mycallback():
print "callback called"
a = worker.Worker()
a.setPyCallback(mycallback)
a.run()
time.sleep(1)
如果我以交互模式运行脚本,例如ipython,它没有问题。
问题:
但是,从python test.py
这样的命令行运行这些脚本只会停留在PyGILState_STATE state = PyGILState_Ensure();
。
如果我理解正确,工作人员正在尝试获取就绪状态来执行回调。虽然不幸的是主要的python线程正忙着睡觉 - 死锁。
问题:我应该在python脚本/ c ++代码中更改什么,以便执行python脚本文件可以请求在c ++中完成任务,稍等一下并异步打印结果?
===================
使用@ Giulio的提示,我现在能够解决问题:PyEval_InitThreads
只能在主线程中调用,而不是c ++管理的线程,正如文档所说。
通过将PyEval_InitThreads();
从lambda移动到函数Worker::run()
的头部,回调部分现在运行完美(使用python主线程休眠)。但是,我需要强调PyEval_InitThreads()
仍然需要run()
。