欢迎来到破竹的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

QThread线程让GUI主线程锁死问题(后来发现是打包前没有qmake和bat脚本中文编码导致的乌龙bug)

问题描述

GUI线程中有一些耗时操作,直接在主线程中执行会使主gui卡死,后来放在QThread线程中执行,子进程中绑定信号槽更新,用进度条显示进程执行的状态,调试的时候是正常运行的,当把程序打包出来执行,子线程开始执行会使gui线程也卡死,界面未响应状态,进度条也不再更新,很让人卧槽的问题。

后来测试了Qt两种线程方法发现问题没有消除,最后发现问题原因是:①打包前没有qmake,导致打包的程序不是最新+②代码中试用的测试进程代码没有删除+③bat脚本中文编码导致bat没有运行,但这些问题在调试的时候正常,打包出来就全部显现,导致后来调试困难,现在记录下qt的线程开启的两种方法

先复现我的导致问题的三个地方

  1. 打包前没有执行qmake,实际生成的exe程序比代码老

  2. 程序打包后bat脚本中文会执行失败,添加chcp 65001 申明下编码

  1. 线程执行返回中开启的测试进程代码没有删
// 线程执行返回
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() ;    //隐藏状态栏进度条
    .....
}
posted @ 2020-07-11 22:32  破竹  阅读(643)  评论(0编辑  收藏  举报