QThread如何優雅實現暫停(掛起)功能

一、實現思路

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


===================================================

===================================================

業餘時間不定期更新一些想法、思考文章,歡迎關注,共同探討,沉澱技術!

            

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章