craig zhang
craig zhang

Reputation: 43

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

In my PyQt5 program, I want to start a new thread running some code:

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()

Where the Slam is written in C++ and converted by pybind11.

And in my main program, the code is triggered by a qAction button:

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

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

Strange thing is that it did indeed started a new thread, done is printed before my Slam progrom. However, when Slam started, the whole program hangs until Slam finished.

In my C++ Slam code, it is like this

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

where startSlam takes few mins to run.

Upvotes: 1

Views: 377

Answers (1)

eyllanesc
eyllanesc

Reputation: 244291

According to the docs when the object is executed in a thread you must call gil_scoped_release and gil_scoped_acquire:

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

Or in the binding:

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

You can find the complete test here

Upvotes: 1

Related Questions