DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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();
 
}
 
 
 
posted on   DoubleLi  阅读(401)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2019-01-30 双网卡单IP实现网卡冗余与负载均衡
2018-01-30 live555源码分析----RSTPServer创建过程分析
点击右上角即可分享
微信分享提示