Qt集成CPython多线程异常:未启动状态机时点击停止致UI卡顿
Qt集成CPython多线程执行异常问题
问题描述
在Qt程序中集成CPython后,多线程执行时出现异常:软件启动后直接点击「停止状态机」按钮,UI会卡顿无响应;但先启动状态机再停止则功能正常。
复现代码
C++代码
// Automatically fetched and automatically released when out of scope class PyGILState { public: PyGILState() : gstate(PyGILState_Ensure()) { } ~PyGILState() { PyGILState_Release(gstate); } PyGILState(const PyGILState&) = delete; PyGILState& operator=(const PyGILState&) = delete; PyGILState_STATE gstate; }; // The class that manages Cpython is moved to a child thread class PythonThread : public QObject { Q_OBJECT public: PythonThread(QObject *parent = nullptr) : QObject(parent) {} ~PythonThread() { } PyObject* module; void newPythonEnv(){ qDebug() << "newPythonEnv thread id : " << QThread::currentThreadId(); Py_SetPythonHome(L"D://python"); // Set your Python installation path Py_SetPath(L"D://python//Lib;D://python//DLLs;D://python;"); Py_Initialize(); PyEval_InitThreads(); // Initialize thread support PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./script')"); module = PyImport_ImportModule("test1"); //Import Python script modules } public slots: // start state machine void start() { qDebug() << "State machine start..."; PyGILState pyGILState; PyObject* pFunc = PyObject_GetAttrString(module, "state_machine"); if (pFunc && PyCallable_Check(pFunc)) { PyObject_CallObject(pFunc, nullptr); } else { PyErr_Print(); std::cerr << "Failed to call state_machine function" << std::endl; } qDebug() << "State machine thread end..."; } // stop state machine void stop() { qDebug() << "State machine stop..."; PyGILState pyGILState; PyObject *globals_dict = PyModule_GetDict(module); if (globals_dict) { PyDict_SetItemString(globals_dict, "isRuning", Py_False); qDebug() << PyLong_AsLong(PyDict_GetItemString(globals_dict, "isRuning")); } else { qDebug() << "Failed to get globals_dict"; } qDebug() << "State machine stopped"; } }; //MainWindow class MainWindow : public QWidget { Q_OBJECT public: MainWindow() { pythonThread = new PythonThread; thread = new QThread; pythonThread->moveToThread(thread); thread->start(); connect(this, &MainWindow::start_thread, pythonThread, &PythonThread::start); connect(this, &MainWindow::new_python_env, pythonThread, &PythonThread::newPythonEnv); qDebug() << "Main thread id: " << QThread::currentThreadId(); emit new_python_env(); QVBoxLayout* layout = new QVBoxLayout(this); QPushButton* startButton = new QPushButton("Start State Machine"); QPushButton* stopButton = new QPushButton("Stop State Machine"); layout->addWidget(startButton); layout->addWidget(stopButton); connect(startButton, &QPushButton::clicked, this, &MainWindow::startStateMachine); connect(stopButton, &QPushButton::clicked, this, &MainWindow::stopStateMachine); setLayout(layout); setWindowTitle("Python State Machine Controller"); } signals: void start_thread(); void new_python_env(); public slots: void startStateMachine() { emit start_thread(); } void stopStateMachine() { pythonThread->stop(); } private: PythonThread* pythonThread; QThread *thread; };
Python脚本代码
import time isRuning = True def state_machine(): global isRuning print('exec ... state machine ',flush=True) isRuning = True isPause = False while isRuning: print(f"state machine runing ... {isRuning}",flush=True) time.sleep(0.1) while isPause == True : print('wait continue ...', flush=True) # time.sleep(1) if isRuning == False : return isRuning = True
(注:原代码缺少import time,此处补充以保证可运行)
控制台输出情况
流程1:先启动再停止(功能正常)
Main thread id: 0x399c newPythonEnv thread id : 0x658 State machine start... exec ... state machine state machine runing ... True state machine runing ... True state machine runing ... True state machine runing ... True state machine runing ... True State machine stop... 0 State machine stopped State machine thread end...
流程2:启动后直接点击停止(UI卡顿)
Main thread id: 0x4b20 newPythonEnv thread id : 0x1070 State machine stop...
此时UI出现卡顿无响应,界面状态如下:
已尝试的解决方法
- 在主线程中创建Python解析器,问题仍未解决。
期望结果
- 「启动状态机」按钮可正常启动Python状态机
- 「停止状态机」按钮可正常终止Python状态机
- 无论按钮点击顺序如何,UI均不会出现卡顿无响应问题
内容的提问来源于stack exchange,提问作者bolin
相关产品推荐
相关产品推荐

