一、前言

在我很久之前的文章【学习QT之多线程编程两种方式详解】中,已经论述过Qt中使用线程的两中方式了。

在子线程中,我们往往希望它干一些费时的任务,所以经常会需要使用死循环。也许你会想到如下写法:

void run()
{
	while(1) {
		//子线程执行任务
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

或者是

bool runFlag;

void run()
{
	while(runFlag) {
		//子线程执行任务
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 方法1:倾向于单片机死循环的写法,但是这种写法实测是无法关闭线程的,使用stop()exit()都无法关闭线程;
  • 方法2:使用标志变量,我们可以通过改变标志变量的状态,来控制子线程任务的执行,这个方法比方法1要好一点,但是也无法精准的控制子线程

二、官方推荐方法

  • 采用isInterruptionRequested()方法控制线程是否停止,该方法只有qt5才具备;
  • 采用锁m_mutex来决定线程是否暂停。
  • 用一个while循环使子线程一直处于运行状态。
  • 如果该线程上运行的任务应该停止,则返回true。可以通过requestinterrupt()请求中断。

线程类

#ifndef TESTTHREAD_H
#define TESTTHREAD_H

#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QDateTime>

class TestThread : public QThread
{
    Q_OBJECT
public:
    TestThread();

    QMutex m_mutex;		//锁
    void pause();		//暂停
    void resume();		//继续
    void exitThread();	//结束

protected:
    void run();
};

#endif // TESTTHREAD_H
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
#include "testthread.h"

TestThread::TestThread()
{

}

void TestThread::run()
{
    while (!this->isInterruptionRequested()) {
        QMutexLocker lock(&m_mutex);

        // to do something
        qDebug()<<QDateTime::currentDateTime();

        msleep(200);
    }

}

void TestThread::pause()
{
    m_mutex.lock();
}

void TestThread::resume()
{
    m_mutex.unlock();
}

void TestThread::exitThread()
{
    this->requestInterruption();
}
  • 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.
  • 32.
  • 33.
  • 34.

Qt线程控制【启动、暂停、继续、退出】_#include

主类调用线程类

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <qDebug>

#include "testthread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public:
    TestThread* testThread{nullptr};

private slots:
    void on_pushButton_start_clicked();

    void on_pushButton_pause_clicked();

    void on_pushButton_resume_clicked();

    void on_pushButton_exit_clicked();

private:
    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H
  • 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.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_start_clicked()
{
    testThread = new TestThread;
    testThread->start();
}

void MainWindow::on_pushButton_pause_clicked()
{
    if(!testThread) {
        return;
    }

    testThread->pause();
}

void MainWindow::on_pushButton_resume_clicked()
{
    if(!testThread) {
        return;
    }

    testThread->resume();
}

void MainWindow::on_pushButton_exit_clicked()
{
    if(!testThread) {
        return;
    }

    testThread->exitThread();

    testThread->wait();

    delete testThread;

    testThread = nullptr;
}
  • 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.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.