为什么 pyqt5 QThread which 运行 pybind11 c++ lib 仍然挂在我的主 GUI 上?

Why pyqt5 QThread which run pybind11 c++ lib still hang my main GUI?

在我的 PyQt5 程序中,我想开始一个新线程 运行 一些代码:

class SlamThread(QThread):
    """docstring for SlamThread"""
    def __init__(self, parent):
        QThread.__init__(self, parent)

    def setSlam(self, params):
        self.params = params

    def run(self):
        self.slam = Slam()
        self.slam.setParams(self.params)
        self.slam.start()

其中Slam是用C++写的,用pybind11转换的

在我的主程序中,代码由 qAction 按钮触发:

def startSlam(self, ...):
        params = ...
        self.thread = SlamThread(self)
        self.thread.setSlam(params)
        self.thread.start()

        for i in range(10):
            print('done')

奇怪的是它确实启动了一个新线程,done 打印在我的 Slam 程序之前。然而,当 Slam 开始时,整个程序挂起,直到 Slam 完成。

在我的C++Slam代码中,是这样的

int Slam::start()
{
    init();
    ...
    startSlam();
    return 0;
}

其中 startSlam 需要几分钟才能到达 运行。

根据docs当对象在线程中执行时你必须调用gil_scoped_release和gil_scoped_acquire:

int Slam::start(){
    pybind11::gil_scoped_release release;
    init();
    // ...
    pybind11::gil_scoped_acquire acquire;
    return 0;
}

或在绑定中:

pybind11::class_<Slam>(mymodule, "Slam")
      .def(pybind11::init<>())
      .def("setParams", &Slam::setParams)
      .def("start", &Slam::start, pybind11::call_guard<pybind11::gil_scoped_release>());

你可以找到完整的测试here