从多线程c ++调用python回调时死锁

时间:2015-02-17 08:51:09

标签: python c++ multithreading boost

假设我通过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()

0 个答案:

没有答案