一、實現思路
QThread中有start、quit,但是沒有pause,那麼我們想要實現這個功能。
- 我們繼承QThread,重寫run();
- 第一反應是不是應該添加個標誌,在run()中判斷暫停狀態。嗯,沒錯,不過我們不能用普通變量,否則有線程非安全風險。這裏使用C++提供的原子類型std::atomic_bool。
- 線程暫停期間,不能空跑消耗cpu,故我們使用Qt條件變量QWaitCondition,配合QMutex。
大概就是這麼點內容吧,實現代碼如下:
Thread.h
#include <QThread>
#include <atomic>
#include <QMutex>
#include <QWaitCondition>
class Thread : public QThread
{
Q_OBJECT
public:
Thread(QObject *parent = nullptr);
~Thread() override;
enum State
{
Stoped, ///<停止狀態,包括從未啓動過和啓動後被停止
Running, ///<運行狀態
Paused ///<暫停狀態
};
State state() const;
public slots:
void start(Priority pri = InheritPriority);
void stop();
void pause();
void resume();
protected:
virtual void run() override final;
virtual void process() = 0;
private:
std::atomic_bool pauseFlag;
std::atomic_bool stopFlag;
QMutex mutex;
QWaitCondition condition;
};
Thread.cpp
#include "Thread.h"
#include <QDebug>
Thread::Thread(QObject *parent)
: QThread(parent),
pauseFlag(false),
stopFlag(false)
{
}
Thread::~Thread()
{
stop();
}
Thread::State Thread::state() const
{
State s = Stoped;
if (!QThread::isRunning())
{
s = Stoped;
}
else if (QThread::isRunning() && pauseFlag)
{
s = Paused;
}
else if (QThread::isRunning() && (!pauseFlag))
{
s = Running;
}
return s;
}
void Thread::start(Priority pri)
{
QThread::start(pri);
}
void Thread::stop()
{
if (QThread::isRunning())
{
stopFlag = true;
condition.wakeAll();
QThread::quit();
QThread::wait();
}
}
void Thread::pause()
{
if (QThread::isRunning())
{
pauseFlag = true;
}
}
void Thread::resume()
{
if (QThread::isRunning())
{
pauseFlag = false;
condition.wakeAll();
}
}
void Thread::run()
{
qDebug() << "enter thread : " << QThread::currentThreadId();
while (!stopFlag)
{
process();
if (pauseFlag)
{
mutex.lock();
condition.wait(&mutex);
mutex.unlock();
}
}
pauseFlag = false;
stopFlag = false;
qDebug() << "exit thread : " << QThread::currentThreadId();
}
- 支持獲取線程狀態;
- start()、stop()、pause()、resume()支持信號槽方式調用;
- start()、stop()、pause()、resume()支持多次無效調用,對線程運行狀態無影響。
- 禁止子類重寫run()方法,而代替爲重寫process()。
二、慣例
測試,運行效果:
可以看到暫停時,PauseQThread.exe的CPU使用率爲0%
代碼地址:
https://gitee.com/bailiyang/cdemo/tree/master/Qt/37PauseQThread/PauseQThread
===================================================
===================================================
業餘時間不定期更新一些想法、思考文章,歡迎關注,共同探討,沉澱技術!