QThread如何优雅实现暂停(挂起)功能

2022-09-02 17:03:42 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

一、实现思路

QThread中有start、quit,但是没有pause,那么我们想要实现这个功能。

  • 我们继承QThread,重写run();
  • 第一反应是不是应该添加个标志,在run()中判断暂停状态。嗯,没错,不过我们不能用普通变量,否则有线程非安全风险。这里使用C 提供的原子类型std::atomic_bool。
  • 线程暂停期间,不能空跑消耗cpu,故我们使用Qt条件变量QWaitCondition,配合QMutex。

大概就是这么点内容吧,实现代码如下:

Thread.h

代码语言:javascript复制
#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

代码语言:javascript复制
#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://javaforall.cn/140496.html原文链接:https://javaforall.cn

0 人点赞