QThread线程让GUI主线程锁死问题(后来发现是打包前没有qmake和bat脚本中文编码导致的乌龙bug)
问题描述
GUI线程中有一些耗时操作,直接在主线程中执行会使主gui卡死,后来放在QThread线程中执行,子进程中绑定信号槽更新,用进度条显示进程执行的状态,调试的时候是正常运行的,当把程序打包出来执行,子线程开始执行会使gui线程也卡死,界面未响应状态,进度条也不再更新,很让人卧槽的问题。
后来测试了Qt两种线程方法发现问题没有消除,最后发现问题原因是:①打包前没有qmake,导致打包的程序不是最新+②代码中试用的测试进程代码没有删除+③bat脚本中文编码导致bat没有运行,但这些问题在调试的时候正常,打包出来就全部显现,导致后来调试困难,现在记录下qt的线程开启的两种方法
先复现我的导致问题的三个地方
-
打包前没有执行qmake,实际生成的exe程序比代码老
-
程序打包后bat脚本中文会执行失败,添加chcp 65001 申明下编码
- 线程执行返回中开启的测试进程代码没有删
// 线程执行返回
void MainWindow::handleResults(QString cmd)
{
//下面这些没删
QProcess p(0);
p.start("cmd", QStringList()<<"cd "+QCoreApplication::applicationDirPath()<<"python PyScript/dealJsonData.py 2");
p.waitForStarted();
p.waitForFinished();
QString strTemp=QString::fromLocal8Bit(p.readAllStandardOutput()); //获得输出
}
Qt线程创建有两种方法,一种是继承QThread,然后重写run的方式,但是这种方式官方已经不推荐了。官方不推荐就不这样写了,推荐第二种方式。使用QObject的moveToThread方法开启线程
1.第一种,使用QThread主线程
线程类定义:
#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H
#include <QThread>
#include <QMutexLocker>
#include<QDebug>
#include <QApplication>
#include <QProcess>
class WorkerThread : public QThread
{
Q_OBJECT
public:
explicit WorkerThread(QObject *parent = 0,QString cmd="")
: QThread(parent),
m_bStopped(false),
commentStr(cmd)
{
qDebug() << "Worker Thread : " << QThread::currentThreadId();
}
~WorkerThread()
{
stop();
quit();
wait();
}
void stop()
{
qDebug() << "Worker Stop Thread : " << QThread::currentThreadId();
QMutexLocker locker(&m_mutex);
m_bStopped = true;
}
protected:
virtual void run() Q_DECL_OVERRIDE {
//qDebug() << "Worker Run Thread : " << QThread::currentThreadId();
int res=QProcess::execute(commentStr.toStdString().c_str());
// 准备更新
emit resultReady(commentStr);
// 检测是否停止
/* {
QMutexLocker locker(&m_mutex);
if (m_bStopped)
return;
}*/
// locker超出范围并释放互斥锁
}
signals:
void resultReady(QString value);
private:
bool m_bStopped;
QMutex m_mutex;
QString commentStr;
};
#endif // WORKERTHREAD_H
线程启动
workerThread = new WorkerThread(this,cmdXml);
connect(workerThread, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
// 线程结束后,自动销毁
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
线程执行结束响应
// 线程执行返回
void MainWindow::handleResults(QString cmd)
{
// qDebug() << "Handle Thread : " << QThread::currentThreadId();
statusProgressBar->hide() ; //隐藏状态栏进度条
.....
}
2.第二种,使用QObject的moveToThread方法开启线程
moveToThreadWorkThread.h
#ifndef MOVETOTHREADWORKTHREAD_H
#define MOVETOTHREADWORKTHREAD_H
#include <QObject>
class moveToThreadWorkThread : public QObject
{
Q_OBJECT
public:
explicit moveToThreadWorkThread(QObject *parent = nullptr,QString cmd="");
~moveToThreadWorkThread();
public slots:
void start1();
void doWork();
signals:
void workFinished();
void workStart();
void resultReady(QString value);
private:
QString commentStr;
};
#endif // MOVETOTHREADWORKTHREAD_H
moveToThreadWorkThread.cpp
#include "movetothreadworkthread.h"
#include <QProcess>
moveToThreadWorkThread::moveToThreadWorkThread(QObject *parent,QString cmd) : QObject(parent),commentStr(cmd)
{
}
moveToThreadWorkThread::~moveToThreadWorkThread()
{
}
void moveToThreadWorkThread::start1()
{
emit workStart();
doWork();
}
void moveToThreadWorkThread::doWork()
{
int res=QProcess::execute(commentStr.toStdString().c_str());
// 准备更新
emit resultReady(commentStr);
emit workFinished();
}
线程开始
QThread* m_workerThread = new QThread();
moveToThreadWorkThread* worker = new moveToThreadWorkThread(nullptr,cmdXml); //第一个参数填nullptr,如果把对象通过 moveToThread 移动到其他线程,这个对象不能有父对象
worker->moveToThread(m_workerThread);
connect(m_workerThread, &QThread::started, worker, &moveToThreadWorkThread::start1);
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
connect(worker, &moveToThreadWorkThread::workFinished, worker, &moveToThreadWorkThread::deleteLater);
connect(worker, &moveToThreadWorkThread::workFinished, m_workerThread, &QThread::quit);
connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater);
m_workerThread->start();
线程执行结束响应
// 线程执行返回
void MainWindow::handleResults(QString cmd)
{
// qDebug() << "Handle Thread : " << QThread::currentThreadId();
statusProgressBar->hide() ; //隐藏状态栏进度条
.....
}