【嵌入式——QT】QThread创建多线程

概述

QThread类提供不依赖于平台的管理线程的方法,一个QThread类的对象管理一个线程,一般从QThread继承一个自定义类,并重定义虚函数run(),在run()函数里实现线程需要完成的任务。
将应用程序的线程称为主线程,额外创建的线程称为工作线程,一般在主线程里创建工作线程,并调用start()开始执行工作线程的任务。start()会在内部调用run()函数,进入工作线程的时间循环,在run()函数调用exit()或quit()可以结束线程的事件循环,或在主线程里调用terminate()强制结束线程。

主要函数

信号

  • void finished():线程结束时发射此信号;
  • void started():线程开始执行、run()函数被调用之前发射此信号;

槽函数

  • quit():退出线程的事件循环,并返回代码0,等效于exit(0);

  • start(QThread::Priority priority = InheritPriority):内部调用run()开始执行线程,操作系统根据Priority参数进行调度;

  • terminate():终止线程的运行,但不是立即结束线程,而是等待操作系统结束线程,使用terminate()之后应使用wait();

    Priority

    • QThread::IdlePriority: 仅在没有其他线程运行时调度;
    • QThread::LowestPriority:比低优先级安排得更少;
    • QThread::LowPriority:比NormalPriority更少被安排;
    • QThread::NormalPriority:操作系统的默认优先级;
    • QThread::HighPriority:比NormalPriority更经常被安排;
    • QThread::HighestPriority:比高优先级安排得更频繁;
    • QThread::TimeCriticalPriority:尽可能多安排时间;
    • QThread::InheritPriority:使用与创建线程相同的优先级。这是默认值;

公共函数

  • bool isFinished() const:线程是否结束;
  • bool isRunning() const:线程是否正在运行;
  • priority() const:返回线程的优先级;
  • setPriority(QThread::Priority priority):设置线程的优先级;
  • exit(int returnCode = 0):退出线程的事件循环;
  • wait(unsigned long time):阻止线程执行,直到线程结束,或等待线程超过time毫秒;

静态公共函数

  • idealThreadCount():返回系统上能运行的线程的理想个数;
  • msleep(unsigned long msecs):强制当前线程休眠msecs毫秒;
  • sleep(unsigned long secs):强制当前线程休眠secs秒;
  • usleep(unsigned long usecs):强制当前线程休眠usecs微秒;

保护函数

  • int exec():由run()函数调用,进入线程的事件循环,等待exit退出;
  • virtual void run():start()调用run()函数开始线程任务的执行,所以在run()函数里实现线程的任务功能;

图示

【嵌入式——QT】QThread创建多线程-LMLPHP

代码示例

QDiceThread.h

#ifndef QDICETHREAD_H
#define QDICETHREAD_H

#include <QObject>
#include <QThread>
#include <QMutex>
class QDiceThread : public QThread
{
    Q_OBJECT

public:
    QDiceThread();
    ~QDiceThread();

    void run() Q_DECL_OVERRIDE;

    void diceBegin();//掷一次骰子
    void dicePause();//暂停
    void stopThread();//结束线程

    bool readValue(int* seq, int* diceValue);

signals:
    void newValue(int seq, int diceValue);//产生新点数的信号


private :
    int m_seq = 0;//掷骰子次数序号
    int m_diceValue;//骰子点数
    bool m_paused = true;//暂停
    bool m_stop = false;//停止

    QMutex mutex;

};

#endif // QDICETHREAD_H

QDiceThread.cpp

#include "QDiceThread.h"
#include <QTime>
#include <QMutexLocker>
QDiceThread::QDiceThread() {}

QDiceThread::~QDiceThread()
{
}

void QDiceThread::run()
{
    m_stop = false;
    m_seq = 0;
    qsrand(QTime::currentTime().msec());
    while(!m_stop) {
        if(!m_paused) {
            //QMutexLocker用法
            // QMutexLocker Locker(&mutex);
            //mutex用法
            mutex.lock();
            m_diceValue = qrand();
            m_diceValue = (m_diceValue % 6)+1;
            m_seq++;
            //使用互斥量读取数据,暂时注释掉信号操作
            // emit newValue(m_seq, m_diceValue);
            //mutex用法
            mutex.unlock();
        }
        msleep(500);
    }
    quit();
}

void QDiceThread::diceBegin()
{
    m_paused = false;
}

void QDiceThread::dicePause()
{
    m_paused = true;
}

void QDiceThread::stopThread()
{
    m_stop = true;
}

bool QDiceThread::readValue(int* seq, int* diceValue)
{
    if(mutex.tryLock()) {
        *seq = m_seq;
        *diceValue = m_diceValue;
        mutex.unlock();
        return true;
    } else {
        return false;
    }
}

QThreadDialog.h

#ifndef QTHREADDIALOG_H
#define QTHREADDIALOG_H

#include <QDialog>
#include "QDiceThread.h"
#include <QTimer>
namespace Ui
{
    class QThreadDialog;
}

class QThreadDialog : public QDialog
{
    Q_OBJECT

public:
    explicit QThreadDialog(QWidget* parent = nullptr);
    ~QThreadDialog();

    void closeEvent(QCloseEvent* event);

private slots:
    void on_pushButtonStart_clicked();

    void on_pushButtonPause_clicked();

    void on_pushButtonBegin_clicked();

    void on_pushButtonStop_clicked();

    void on_pushButtonClear_clicked();

public slots:
    void threadStatusStart();

    void threadStatusFinished();

    void threadNewValue(int seq, int diceValue);

    void onTimeOut();

private:
    Ui::QThreadDialog* ui;
    QDiceThread thread;

    QTimer timer;

    int mSeq, mDiceValue;
};

#endif // QTHREADDIALOG_H

QThreadDialog.cpp

#include "QThreadDialog.h"
#include "ui_QThreadDialog.h"

QThreadDialog::QThreadDialog(QWidget* parent)
    : QDialog(parent)
    , ui(new Ui::QThreadDialog)
{
    ui->setupUi(this);
    connect(&thread, SIGNAL(started()), this, SLOT(threadStatusStart()));
    connect(&thread, SIGNAL(finished()), this, SLOT(threadStatusFinished()));
    connect(&thread, &QDiceThread::newValue, this, &QThreadDialog::threadNewValue);
    connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
}

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

void QThreadDialog::closeEvent(QCloseEvent* event)
{
    if(thread.isRunning()) {
        thread.stopThread();
        thread.wait();
    }
    event->accept();
}

void QThreadDialog::on_pushButtonStart_clicked()
{
    thread.start();
    mSeq = 0;
    ui->pushButtonStart->setEnabled(false);
    ui->pushButtonStop->setEnabled(true);
    ui->pushButtonBegin->setEnabled(true);
    ui->pushButtonPause->setEnabled(false);
}

void QThreadDialog::on_pushButtonStop_clicked()
{
    thread.stopThread();
    thread.wait();
    ui->pushButtonStart->setEnabled(true);
    ui->pushButtonStop->setEnabled(false);
    ui->pushButtonBegin->setEnabled(false);
    ui->pushButtonPause->setEnabled(false);
}


void QThreadDialog::on_pushButtonBegin_clicked()
{
    thread.diceBegin();
    timer.start(100);
    ui->pushButtonBegin->setEnabled(false);
    ui->pushButtonPause->setEnabled(true);
}

void QThreadDialog::on_pushButtonPause_clicked()
{
    thread.dicePause();
    timer.stop();
    ui->pushButtonBegin->setEnabled(true);
    ui->pushButtonPause->setEnabled(false);
}



void QThreadDialog::on_pushButtonClear_clicked()
{
    ui->plainTextEdit->clear();
}

void QThreadDialog::threadStatusStart()
{
    ui->labelStatus->setText("thread started");
}

void QThreadDialog::threadStatusFinished()
{
    ui->labelStatus->setText("thread finished");
}

void QThreadDialog::threadNewValue(int seq, int diceValue)
{
    QString str = QString::asprintf(u8"第%d次投掷骰子,点数为:%d", seq, diceValue);
    ui->plainTextEdit->appendPlainText(str);
}

void QThreadDialog::onTimeOut()
{
    int tmpSeq =0, tmpValue = 0;
    bool valid = thread.readValue(&tmpSeq, &tmpValue);
    if(valid && (tmpSeq != mSeq)) {
        mSeq = tmpSeq;
        mDiceValue = tmpValue;
        QString str = QString::asprintf(u8"第%d次投掷骰子,点数为:%d", mSeq, mDiceValue);
        ui->plainTextEdit->appendPlainText(str);
    }
}




03-14 17:57