在多线程环境中使用 Qt C++ 调用 Python

  1. 初始化和终止 Python 解释器
    在使用任何 Python API 之前,必须初始化 Python 解释器。

    • 确保 Py_InitializePy_Finalize 只调用一次,通常在程序的生命周期内。
    • 可以使用静态变量或单例模式来管理 Python 解释器的初始化和终止。
    if(!Py_IsInitialized()) // 判断 Python 解释器是否已经初始化
    {
        Py_Initialize();    // 初始化 Python 解释器
    }
    // ... 进行 Python 对象的操作 ...
    Py_Finalize();          // 结束程序时再终止 Python 解释器
    
  2. 全局解释器锁(GIL)
    如果在多线程环境中使用 Python 解释器,需要确保线程安全。可以使用 PyGILState_EnsurePyGILState_Release 来管理全局解释器锁(GIL)。

    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure(); // 获取 GIL
    // ... 进行 Python 对象的操作 ...
    PyGILState_Release(gstate);   // 释放 GIL
    

    PyGILState_STATE 用起来各种问题,不如使用互斥锁。

    static QMutex mutex;
    QMutexLocker locker(&mutex);
    // ... 进行 Python 对象的操作 ...
    

    暂时记录(有时间再来研究):

    1. QRunnableQThreadPool 中使用 PyGILState_Ensure 会导致死锁。
    2. 换成QThread能解决死锁问题,但是获取GIL后面的代码都没有再执行,当结束程序时会报:
      QCoreApplication::applicationDirPath: Please instantiate the QApplication object first
      
      或者
      Fatal Python error: PyEval_SaveThread: NULL tstate
      Python runtime state: initialized
      
      要么直接关闭程序,控制台 return 1
    3. 调用 Python 封装成了单例类,关系应该不大。

    可以参考:
    链接: C++ 多线程调用Python脚本
    链接: 记QT混编c++多次调用python脚本所出现的问题
    链接: qt(c++)线程中调用python

总结:

  1. 使用单例模式管理 Python 解释器的初始化和终止,确保只调用一次。
  2. 在执行 Python 代码时使用 QMutexLocker 进行互斥锁管理,确保线程安全。
  3. 在获取 GIL 后添加错误处理机制,确保在出现异常时能够正确释放 GIL。
  4. 使用 QThread 来管理线程,避免在 QRunnableQThreadPool 中使用 PyGILState_Ensure 导致的死锁问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值