QThread之重寫run() 實現線程與業務解耦

一、線程的一般實現形式

Qt中線程類QThread有2種使用方式。

1.繼承自QThread,重寫run()

 class MyThread : public QThread
 {
     Q_OBJECT
 protected:
     virtual void run() override { ... }
 };

我們一般在run()中加個死循環,不停處理業務或者調用相關的方法。這樣的話,我們的業務邏輯與線程緊密耦合在一起。

適用場景:

用於一直不停處理業務,而不是處理完一單業務後,就可以休眠的這種場景。

2.moveToThread

使用一個QObject作爲Worker,並moveToThread到線程上。

此種方式不在本文討論範圍內,故不贅述。

二、抽象業務邏輯

我們的業務是需要掛在線程上跑的,那麼業務應該有個可執行接口,以實現掛接到線程上。那簡單,來一個接口。

IRunable.h

class IRunable
{
public:
    virtual ~IRunable() {}
    virtual void exec() = 0;
};

業務,我們也叫它任務,定義2個任務。

class Task1 : public IRunable
{
public:
    virtual void exec() override
    {
        qDebug() << "do Task1...";
    }
};

class Task2 : public IRunable
{
public:
    virtual void exec() override
    {
        qDebug() << "do Task2...";
    }
};

我們這裏使用的線程類是Thread,它派生於QThread,只不過重寫的是Thread::process(),與使用QThread無異。

我們自定義Executor執行器類,繼承自Thread,原理是通過addRunable(IRunable *able)添加可執行對象到QList<IRunable *>裏面,然後在線程執行函數process()中,依次執行list中的對象。

Executor.cpp

Executor::Executor(QObject *parent)
    : Thread(parent)
{

}

Executor::~Executor()
{
    Thread::stop();
}

void Executor::addRunable(IRunable *able)
{
    runableList.append(able);
}

void Executor::addRunables(const QList<IRunable *> &ables)
{
    runableList.append(ables);
}

QList<IRunable *> Executor::getRunables()
{
    return runableList;
}

void Executor::process()
{
    foreach (auto able, runableList)
    {
        able->exec();
    }
}

代碼比較簡單,這樣做,可以讓任務與線程之間依賴於接口,而不依賴於實現,實現線程與業務邏輯解耦。此後對任務的擴展,不牽涉到線程,且可以實現單線程-多任務,多線程-多任務的靈活配置。

另外,多線程對於共享數據的競爭保護,也可以在各自的任務實現類中,進行處理。

三、測試

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    executor = new Executor();

    runableList.append(new Task1());
    runableList.append(new Task2());
    executor->addRunables(runableList);
}

MainWindow::~MainWindow()
{
    delete executor;
    executor = nullptr;
    qDeleteAll(runableList);
    runableList.clear();
    delete ui;
}

void MainWindow::on_pushButton_start_clicked()
{
    executor->start();
}

void MainWindow::on_pushButton_pause_clicked()
{
    executor->pause();
}

void MainWindow::on_pushButton_stop_clicked()
{
    executor->stop();
}

void MainWindow::on_pushButton_resume_clicked()
{
    executor->resume();
}

void MainWindow::on_pushButton_clicked()
{
    Thread::State s = executor->state();
    if (s == Thread::Stoped)
    {
        qDebug() << "state : Stoped";
    }
    else if (s == Thread::Running)
    {
        qDebug() << "state : Running";
    }
    else if (s == Thread::Paused)
    {
        qDebug() << "state : Paused";
    }
}

運行效果:
在這裏插入圖片描述

代碼地址:

https://gitee.com/bailiyang/cdemo/tree/master/Qt/37PauseQThread/PauseQThread


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

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

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

            

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