代码之家  ›  专栏  ›  技术社区  ›  MHDtA

在其他线程(使用QThread)中使用pybind11时,应用程序崩溃

  •  0
  • MHDtA  · 技术社区  · 2 年前

    我有一个嵌入式模块,类为:

    
    PYBIND11_EMBEDDED_MODULE(appmodule, m) {
    
        py::class_<Camera>(m, "Camera")
                .def(py::init<>())
                .def("onFrameEvent", &Camera::onFrameEvent, pybind11::call_guard<pybind11::gil_scoped_release>());
    }
    
    

    正如文档中所述,在使用多线程时,我添加了 pybind11::call_guard<pybind11::gil_scoped_release>() .

    接下来,我有一个继承QThread的类,它重载了 run() 方法:

    class Worker : public QThread {
    
            Q_OBJECT
    
            public:
                Worker(Camera* cam);
                void run();
    
            private:
                Camera* camera;
        };
    
    
    void Worker::run() {
    
        // Next code runs in other thread:
    
        QTimer* loop = new QTimer();
        connect(loop, &QTimer::timeout, [=]() {
            cv::Mat m = camera->getOpenCVMat();
            py::array_t<uint8_t> output(
                    py::buffer_info(
                            m.data,
                            sizeof(uint8_t),
                            py::format_descriptor<uint8_t>::format(),
                            3,
                            std::vector<size_t> {static_cast<unsigned long>(m.rows), static_cast<unsigned long>(m.cols), 3},
                            std::vector<size_t> { sizeof(uint8_t) * static_cast<unsigned long>(m.cols) * 3, sizeof(uint8_t) * 3, sizeof(uint8_t)}));
        
            camera->getPythonHandle().attr("onFrameEvent")(output); // Call event on python side
        });
        
        loop->start(1000);
    
    
        QThread::exec();
    }
    

    python方面:

    import appmodule
    import cv2
    
    
    class MyCamera(appmodule.Camera):
        def __init__(self):
            super().__init__()
    
        def onFrameEvent(self, image):
            cv2.imshow('', image)
    

    为了初始化解释器,我使用 py::initialize_interpreter(); 在开始 main() 功能。

    问题是应用程序崩溃,并显示以下消息:

    pybind11::handle::inc_ref()正在被调用,而GIL是 未持有或无效。请看 https://pybind11.readthedocs.io/en/stable/advanced/misc.html#common-sources-of-global-interpreter-lock-errors 获取调试建议。

    如果你确信你的电脑里没有bug 代码,您可以#定义PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DEF 禁用此检查。在这种情况下,你必须确保这个#define是 始终用于链接到给定翻译单元的所有翻译单元 pybind11扩展,否则将出现ODR违规。失败 函数对象上触发了pybind11::handle::inc_ref()调用。

    调用pybind11::handle::dec_ref()时,GIL为 未持有或无效。请看 https://pybind11.readthedocs.io/en/stable/advanced/misc.html#common-全局解释器锁错误的来源 获取调试建议。如果你确信你的电脑里没有bug 代码,您可以#定义PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DEF 禁用此检查。在这种情况下,你必须确保这个#define是 始终用于链接到给定翻译单元的所有翻译单元 pybind11扩展,否则将出现ODR违规。失败 函数对象上触发了pybind11::handle::dec_ref()调用。

    libc++abi:由于类型的未捕获异常而终止 std::runtime_error:pybind11::handle::dec_ref()PyGILState_Check() 失败。

    尝试定义PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF时,崩溃不会消失,但消息中只显示以下内容:

    libc++abi:由于std::runtime_error类型的未捕获异常而终止:pybind11::handle::dec_ref()PyGILState_Check()失败。

    我还试图添加 py::gil_scoped_release release; 在开始 run() 方法,但它没有解决问题

    系统:MacOS Ventura

    1 回复  |  直到 2 年前
        1
  •  1
  •   Ahmed AEK    2 年前

    在开始操作python对象之前,您需要在lambda(线程)中获取GIL。

    connect(loop, &QTimer::timeout, [=]() {
    py::gil_scoped_acquire guard{}
    ...
    });