1、背景
简单说一下需求,Qt开发的上位机界面程序,需要调用Python编写的算法跑一个结果返回到界面上显示。
2、度娘出一篇博客,按照步骤进行环境搭建和简单的代码测试
环境搭建请参照如下博客地址:
博客:① https://blog.csdn.net/cholenmine/article/details/82854301
② https://blog.csdn.net/yinyuchen1/article/details/77775851
qDebug()<<"11111111111111111111";
PyObject *pModule = PyImport_ImportModule("myModule");
qDebug()<<"2222222222222222";
PyObject * pFuncHello = PyObject_GetAttrString(pModule, "greatFunc");
qDebug()<<"3333333333333333333333";
3、根据目前的具体需求,我需要在开启一个线程来调用Python脚本,于是用qt内部的信号槽来使用线程调用,调用方法还是用的上面的示例代码。
.h文件
void Widget::handleLoadGCode(QString str)
pQwait->SetShowText(u8"提示", u8"加载G代码中,请稍后");
m_consuming->PythonInit();
qDebug() << "python环境已经初始化了";
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);
线程类一定要是继承自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
nStatus = PyGILState_Check();
gstate = PyGILState_Ensure();
_save = PyEval_SaveThread();
PyEval_RestoreThread(_save);
_save = PyEval_SaveThread();
PyEval_RestoreThread(_save);
PyGILState_Release(gstate);
2:然后写个PythonInit函数,这个函数只调一次就行了。
void Robot_time_consuming::PythonInit()
if (!Py_IsInitialized()) {
qDebug("初始化Python解释器失败");
PyRun_SimpleString("import sys");
QString setSysPath = QString("sys.path.append('%1')").arg(QCoreApplication::applicationDirPath());
PyRun_SimpleString(setSysPath.toStdString().c_str());
PyEval_ReleaseThread(PyThreadState_Get());
qDebug("初始化Python解释器成功");
3:然后再你调用python函数的地方这样写,记住,之前的
Py_Finalize(),要删除;
void Robot_time_consuming::LoadGCode(QString GName)
class PyThreadStateLock PyThreadLock;
PyObject* pModule = PyImport_ImportModule("TransferKRL");
QString infoData = "Can not open python file!";
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);
qDebug() << "res:" << res;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2019-01-30 双网卡单IP实现网卡冗余与负载均衡
2018-01-30 live555源码分析----RSTPServer创建过程分析