首页 > 编程语言 >QT(c++) 线程 调用python问题

QT(c++) 线程 调用python问题

时间:2023-01-30 17:33:25浏览次数:49  
标签:consuming 调用 QT python c++ Python 线程 GIL PyEval

1、背景

  简单说一下需求,Qt开发的上位机界面程序,需要调用Python编写的算法跑一个结果返回到界面上显示。

2、度娘出一篇博客,按照步骤进行环境搭建和简单的代码测试

  环境搭建请参照如下博客地址:

    博客:① https://blog.csdn.net/cholenmine/article/details/82854301

       ② https://blog.csdn.net/yinyuchen1/article/details/77775851

 

 
  #include "Python.h"       void MainWindow::test()       {   //进行初始化       Py_Initialize();       //如果初始化失败,返回       if(!Py_IsInitialized())       {           qDebug()<<"11111111111111111111";           return ;   }       //加载模块,模块名称为myModule,就是myModule.py文件   PyObject *pModule = PyImport_ImportModule("myModule");   //如果加载失败,则返回       if(!pModule)       {           qDebug()<<"2222222222222222";           return;       }          //加载函数greatFunc       PyObject * pFuncHello = PyObject_GetAttrString(pModule, "greatFunc");       //如果失败则返回       if(!pFuncHello)       {           qDebug()<<"3333333333333333333333";           return ;   }   Py_Finalize();   }
 
 

 

3、根据目前的具体需求,我需要在开启一个线程来调用Python脚本,于是用qt内部的信号槽来使用线程调用,调用方法还是用的上面的示例代码。

  .h文件

 
  void Widget::handleLoadGCode(QString str)   {   m_loadGCodeClick = true;   pQwait->SetShowText(u8"提示", u8"加载G代码中,请稍后");   pQwait->show();       if (!m_isInitPy)   m_consuming->PythonInit();   else   qDebug() << "python环境已经初始化了";       m_isInitPy = true;   QThread *thread = new QThread;       connect(thread, &QThread::started, [=]() {   m_consuming->LoadGCode(str);   });       connect(m_consuming, SIGNAL(successed()), this, SLOT(handleTimeConsumingEnd()));   connect(m_consuming, SIGNAL(successed()), thread, SLOT(quit()));   connect(m_consuming, SIGNAL(failed()), this, SLOT(handleTimeConsumingFailed()));   connect(m_consuming, SIGNAL(failed()), thread, SLOT(quit()));   connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));   m_consuming->moveToThread(thread);   thread->start();       }
 
 

线程类一定要是继承自qobject的,就行了。

现在问题来了:

  ① 第一次调用python脚本,能够正常调用并且得到结果。

  ② 不关闭主界面,接着进行第二次调用,软件直接崩溃,崩溃的行数是PyImport_ImportModule()函数。

 

最开始分析的原因:① 出现了空指针 

         ② 第二次调用时,第一次的资源没有释放,占用python脚本,导致PyImport_ImportModule()函数不能将模块导入

4、最后差资料发现,因为我这里使用的是线程,C++多线调用python时必须要控制GIL

 

参照如下博客的方法才得以解决这个问题,对于小白初次线程中调用Python,鬼知道要控制什么GIL,虽然问题解决了,到现在都没去看GIL是个什么鬼  

  https://blog.csdn.net/qq_42938320/article/details/101770269

 

解决方法 :

1:先新建一个.h文件:如下

 
  //将全局解释器锁和线程的相关操作用类封装   #ifndef PYTHREADSTATELOCK_H   #define PYTHREADSTATELOCK_H   #include "Python.h"       class PyThreadStateLock   {   public:   PyThreadStateLock(void)   {   _save = nullptr;   nStatus = 0;   nStatus = PyGILState_Check(); //检测当前线程是否拥有GIL   PyGILState_STATE gstate;   if (!nStatus)   {   gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL   nStatus = 1;   }   _save = PyEval_SaveThread();   PyEval_RestoreThread(_save);   }   ~PyThreadStateLock(void)   {   _save = PyEval_SaveThread();   PyEval_RestoreThread(_save);   if (nStatus)   {   PyGILState_Release(gstate); //释放当前线程的GIL   }   }       private:   PyGILState_STATE gstate;   PyThreadState *_save;   int nStatus;       };       #endif // PYTHREADSTATELOCK_H
 
 

 

2:然后写个PythonInit函数,这个函数只调一次就行了。

 
  void Robot_time_consuming::PythonInit()   {   if (!Py_IsInitialized())   {   //1.初始化Python解释器,这是调用操作的第一步   Py_Initialize();   if (!Py_IsInitialized()) {   qDebug("初始化Python解释器失败");   emit failed();   }   else {       //执行单句Python语句,用于给出调用模块的路径,否则将无法找到相应的调用模块   PyRun_SimpleString("import sys");   QString setSysPath = QString("sys.path.append('%1')").arg(QCoreApplication::applicationDirPath());   PyRun_SimpleString(setSysPath.toStdString().c_str());   // 初始化线程支持   PyEval_InitThreads();   // 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。   PyEval_ReleaseThread(PyThreadState_Get());   qDebug("初始化Python解释器成功");   }   }       }
 
 

3:然后再你调用python函数的地方这样写,记住,之前的

Py_Finalize(),要删除;

 

  void Robot_time_consuming::LoadGCode(QString GName)   {   class PyThreadStateLock PyThreadLock;//获取全局锁       //导入TransferKRL.py模块   PyObject* pModule = PyImport_ImportModule("TransferKRL");   if (!pModule) {   QString infoData = "Can not open python file!";   qDebug() << infoData;   emit failed();   return;   }           PyObject *pyClass = PyObject_GetAttrString(pModule, "GcodeToTrack");   PyObject *pConstruct = PyInstanceMethod_New(pyClass);           PyObject* pParams = PyTuple_New(2);   PyTuple_SetItem(pParams, 0, Py_BuildValue("s", GName.toStdString().c_str()));   PyTuple_SetItem(pParams, 1, Py_BuildValue("s", "trackFile01.csv"));   PyObject* pIns = PyObject_CallObject(pConstruct, pParams);               int res = 0;   // PyArg_Parse(FuncTwoBack,"i",&res);//转换返回类型   qDebug() << "res:" << res;   emit successed();   }
 
   

标签:consuming,调用,QT,python,c++,Python,线程,GIL,PyEval
From: https://www.cnblogs.com/lidabo/p/17076768.html

相关文章

  • 用python制作一个简单的zip压缩工具
    1.功能设计对文件或文件夹压缩,是日常工作中经常要做的事情,市面上也有非常多的压缩工具,在linux系统里,有zip,tar等命令可以用于压缩。最近学习了python的zipfile模块,它提供......
  • 掌握hashtable,深度理解python字典的数据结构
    文章目录​​1.hash函数​​​​2.hashtable​​​​2.1链地址法实现hashtable​​​​2.2解决冲突​​​​2.3开放寻址法实现hashtable​​​​2.4逻辑删除key​​​......
  • 忘掉python的os.path吧,pathlib巨好用
    1.pathlib取代os.path模块从python3.4开始,pathlib正式成为标准库,旨在取代老旧的os.path模块和一些os模块中对系统路径的操作。pathlib提供了表示文件系统路径的类,而os.pat......
  • python web框架多进程部署下数据库连接问题
    python常用的web框架,诸如flask,django,在生产部署时,都会选择多进程的部署方式,选用的中间件多为uwsgi或者gunicorn。如果项目里使用了数据库,那么就要考虑数据库连接在多进程下......
  • python使用正则表达式实现字符串替换
    python的字符串提供了replace方法,可以将子串替换成其他字符串,例如下面的代码name='flask_script'name=name.replace('_','-')print(name)#flask-script替换的前提......
  • C++子线程中调用python代码
    项目需要C++调用python的算法,由于python算法比较耗时,因此采用在C++里启动workingthread来调用python脚本,python代码里含有cv2.imread()等opencv的调用,在子线程里调用会卡......
  • 【Python笔记2.1】Python Unicode字符编解码
    以下部分参考[1],这里复制了其中一部分是为了防止原文被移动或删除。概述Python中有字符串类型(str)和字节类型(byte),以及Python编码中最常见也是最顽固的两个错误:Unic......
  • 【Python笔记2.2】用zipfile解压zip包时遇到的Unicode字符编解码问题
    pythonunicode字符编解码问题参见【Python笔记2.1】python中用zipfile解压zip包网上资料一堆,这里就不多说了。下面使用【Python笔记2.1】中总结出来的字符编解码函数......
  • 【KAWAKO】python查看内存空间占用情况
    目录查看变量的内存占用查看运行内存占用查看变量的内存占用importsysc=1145.114print(sys.getsizeof(c))查看运行内存占用importpsutilmemory=psutil.vir......
  • python实用小技之数据结构
     本文大多数例子搬自pythoncookbook这里是对学习的一个总结和提炼ps:python版本为python3 1.解压序列赋值给多个变量#有一个包含N个元素的元组或者是序列,怎样将......