概述
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()函数里实现线程的任务功能;
图示
代码示例
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);
}
}