Qt でマルチスレッドを使用する 4 つの方法とコード例のまとめ


序文

以前の Qt 開発作業で、マルチスレッドの使用が比較的一般的であることがわかりましたので、ここでは、私のこれまでの経験と他のブログ記事を参考にして得た経験をまとめ、Qt でマルチスレッドを実現するためのいくつかの方法をまとめます。誰もが学び、間違いがあれば、誰もが批判して修正することができます。

1. QThread を継承し、run() 関数を書き換えます;
2. QObject を継承し、moveToThread() 関数を使用します;
3. QRunnable を継承し、run() 関数を書き換えて、QThreadPool スレッド プールを使用します;
4. run() 関数を使用しますQtConcurrent の関数。

プロジェクトの効果
インターフェイス上の 4 つのグループ ボックスにある [開始] ボタンを順番にクリックすると、下図のような出力が表示されます。プログラムがスレッド番号に従って 4 つのスレッドを正常に開始したことがわかります。また、もう一度クリックすると、プログラムが正常に開始されたことがわかります。 , QRunnable メソッドと QtConcurrent メソッドを再度開くことができます。新しいスレッドの場合、開くことができるスレッドの数は現在のスレッド プール設定に関係します。
画像の説明を追加してください


提示:以下是本篇文章正文内容,下面案例可供参考

1. QThread を継承して run() 関数を書き直す

1.qthreadrun.h

#ifndef QTHREADRUN_H
#define QTHREADRUN_H

#include <QThread>
#include <QDebug>

class QThreadRun : public QThread
{
    
    
    Q_OBJECT

public:
    QThreadRun();
    ~QThreadRun();

    void setSwitch(bool flag);
    void run();

private:
    bool startFlag;
};
#endif // QTHREADRUN_H

2.qthreadrun.cpp

#include "qthreadrun.h"

QThreadRun::QThreadRun()
{
    
    
    startFlag = false;
}

QThreadRun::~QThreadRun()
{
    
    

}

void QThreadRun::setSwitch(bool flag)
{
    
    
    startFlag = flag;
}

void QThreadRun::run()
{
    
    
    while(startFlag)
    {
    
    
        qDebug()<<"QThreadRun子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);   //延时1000ms
    }
}

2. QObject を継承し、moveToThread() 関数を使用します。

1.qmovetothread.h

#ifndef QMOVETOTHREAD_H
#define QMOVETOTHREAD_H

#include <QObject>
#include <QThread>
#include <QDebug>

class QMoveToThread : public QObject
{
    
    
    Q_OBJECT

public:
    QMoveToThread();
    ~QMoveToThread();

    void setSwitch(bool flag);

public slots:
    void slot_moveToThread();

private:
    bool startFlag;
};
#endif // QMOVETOTHREAD_H

2.qmovetothread.cpp

#include "qmovetothread.h"

QMoveToThread::QMoveToThread()
{
    
    
    startFlag = false;
}

QMoveToThread::~QMoveToThread()
{
    
    

}

void QMoveToThread::setSwitch(bool flag)
{
    
    
    startFlag = flag;
}

void QMoveToThread::slot_moveToThread()
{
    
    
    while(startFlag)
    {
    
    
        qDebug()<<"QMoveToThread子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

3. QRunnable を継承し、run() 関数を書き換えて、QThreadPool スレッド プールを使用します。

1.qrunnablerun.h

#ifndef QRUNNABLERUN_H
#define QRUNNABLERUN_H

#include <QRunnable>
#include <QThread>
#include <QDebug>

class QRunnableRun : public QRunnable
{
    
    
public:
    QRunnableRun();
    ~QRunnableRun();

    void setSwitch(bool flag);
    void run();

private:
    bool startFlag;
};
#endif // QRUNNABLERUN_H

2.qrunnablerun.cpp

#include "qrunnablerun.h"

QRunnableRun::QRunnableRun()
{
    
    
    startFlag = false;
}

QRunnableRun::~QRunnableRun()
{
    
    

}

void QRunnableRun::setSwitch(bool flag)
{
    
    
    startFlag = flag;
}

void QRunnableRun::run()
{
    
    
    while(startFlag)
    {
    
    
        qDebug()<<"QRunnableRun子线程号:"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

4番目に、QtConcurrentのrun()関数を使用します。

1. プロジェクト file.pro ファイルに次のコードを追加します。

QT   += concurrent

2. ヘッダーファイルを追加します

#include <QtConcurrent>

3. 使用方法

...
//详细代码见下文
QtConcurrent::run(this,&Widget::myQtConcurrentRun);
...

5. コード例

1.Qスレッドテスト.プロ

QT   += core gui
QT   += concurrent

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
    main.cpp \
    qmovetothread.cpp \
    qrunnablerun.cpp \
    qthreadrun.cpp \
    widget.cpp

HEADERS += \
    qmovetothread.h \
    qrunnablerun.h \
    qthreadrun.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${
    
    TARGET}/bin
else: unix:!android: target.path = /opt/$${
    
    TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.ウィジェット.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThreadPool>
#include <QtConcurrent>
#include "qthreadrun.h"
#include "qmovetothread.h"
#include "qrunnablerun.h"

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    
    
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void initThread();

    void setSwitch(bool flag);
    void myQtConcurrentRun();
    void myMainRun();

signals:
    void signal_moveToThread();

private slots:
    void on_pb_start_clicked();
    void on_pb_stop_clicked();
    void on_pb_start_2_clicked();
    void on_pb_stop_2_clicked();
    void on_pb_start_3_clicked();
    void on_pb_stop_3_clicked();
    void on_pb_start_4_clicked();
    void on_pb_stop_4_clicked();
    void on_pb_test_clicked();

private:
    Ui::Widget *ui;

    //QThreadRun
    QThreadRun *m_QThreadRun;

    //QMoveToThread
    QThread *m_QThread;
    QMoveToThread *m_QMoveToThread;

    //QRunnableRun
    QThreadPool *m_QThreadPool;
    QRunnableRun *m_QRunnableRun;

    //QtConcurrentRun
    bool startFlag;
};
#endif // WIDGET_H

3.ウィジェット.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    
    
    ui->setupUi(this);
    this->initThread();
}

Widget::~Widget()
{
    
    
    delete ui;
}

void Widget::initThread()
{
    
    
    //main
    qDebug()<<"Widget主线程号:"<<QThread::currentThread();

    //QThreadRun
    m_QThreadRun = new QThreadRun();

    //QMoveToThread
    m_QThread = new QThread(this);
    m_QMoveToThread = new QMoveToThread();
    connect(this,SIGNAL(signal_moveToThread()),m_QMoveToThread,SLOT(slot_moveToThread()),Qt::UniqueConnection);
    m_QMoveToThread->moveToThread(m_QThread);
    m_QThread->start();

    //QRunnableRun
    m_QThreadPool = new QThreadPool();
    m_QThreadPool->setMaxThreadCount(3);   //设置非全局线程池可容纳线程个数为3个
    m_QRunnableRun = new QRunnableRun();

    //QtConcurrentRun
    startFlag = false;
    //qDebug()<<QThreadPool::globalInstance()->maxThreadCount();   //获取全局线程池最大线程个数
    //QThreadPool::globalInstance()->setMaxThreadCount(10);        //设置全局线程池可容纳线程个数

}

void Widget::setSwitch(bool flag)
{
    
    
    startFlag = flag;
}

void Widget::myQtConcurrentRun()
{
    
    
    while(startFlag)
    {
    
    
        qDebug()<<"QtConcurrent子线程号"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

void Widget::myMainRun()
{
    
    
    while(startFlag)
    {
    
    
        qDebug()<<"当前线程号"<<QThread::currentThread();
        QThread::msleep(1000);
    }
}

//QThreadRun
void Widget::on_pb_start_clicked()
{
    
    
    m_QThreadRun->setSwitch(true);
    m_QThreadRun->start();
}

void Widget::on_pb_stop_clicked()
{
    
    
    m_QThreadRun->setSwitch(false);
}

//QMoveToThread
void Widget::on_pb_start_2_clicked()
{
    
    
    m_QMoveToThread->setSwitch(true);
    //m_QMoveToThread->slot_moveToThread();   不能直接调用处理函数,函数还是在主线程中运行
    emit signal_moveToThread();   //发送信号启动子线程处理函数
}

void Widget::on_pb_stop_2_clicked()
{
    
    
    m_QMoveToThread->setSwitch(false);
}

//QRunnableRun
void Widget::on_pb_start_3_clicked()
{
    
    
    m_QRunnableRun->setSwitch(true);

    //全局线程池方式
    //QThreadPool::globalInstance()->start(m_QRunnableRun);
    //qDebug()<<"全局线程池当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount();   //当前活动的线程个数

    //非全局线程池方式
    m_QThreadPool->start(m_QRunnableRun);
    qDebug()<<"非全局线程池当前线程数:"<<m_QThreadPool->activeThreadCount();   //当前活动的线程个数

}

void Widget::on_pb_stop_3_clicked()
{
    
    
    m_QRunnableRun->setSwitch(false);
}

//QtConcurrentRun
void Widget::on_pb_start_4_clicked()
{
    
    
    setSwitch(true);
    QtConcurrent::run(this,&Widget::myQtConcurrentRun);
    qDebug()<<"QtConcurrentRun当前线程数:"<<QThreadPool::globalInstance()->activeThreadCount();   //当前活动的线程个数
}

void Widget::on_pb_stop_4_clicked()
{
    
    
    setSwitch(false);
}

//不使用多线程的对比测试,界面卡死
void Widget::on_pb_test_clicked()
{
    
    
    setSwitch(true);
    myMainRun();
}

4.ウィジェット.ui
画像の説明を追加してください

6. ダウンロードリンク

私の Baidu ネットワーク ディスク リンクの例: https://pan.baidu.com/s/1hpcXFA2vahZ0WV3pRUfqXQ
抽出コード: xxcj


要約する

上記のマルチスレッド実現方法では、QtConcurrent の run() 関数を使用した方がクラスの継承も関数の書き換えも必要なく、より便利に利用できることがわかります。このメソッドで取得されたスレッドは QThreadPool プールから取得されたものです QThreadPool プールにアイドル状態のスレッドがない場合、スレッドは直接実行されない可能性があります。QRunnable の run() を使用すると、開始するグローバル スレッド プールと非グローバル スレッド プールがあることがわかります。グローバル スレッド プールは、QtConcurrent メソッドの QThreadPool と同じです。スレッド プールに関するいくつかの関数出力を次に示します。
QThreadPool::globalInstance()->maxThreadCount(); //スレッド プール内のスレッドの最大数を取得します
QThreadPool::globalInstance()->setMaxThreadCount(10); //スレッド プールが収容できるスレッド数を設定します
QThreadPool::globalInstance() ->activeThreadCount(); //現在のスレッド プール内のアクティブなスレッドの数
Qt でのマルチスレッドのいくつかの方法の長所と短所の詳細については、参考記事を確認してください。


こんにちは:
一緒に学び、一緒に進歩しましょう。関連する質問がまだある場合は、ディスカッションのためにコメント領域にメッセージを残すことができます。

参考ブログ:
Qt の 4 つのマルチスレッド実装
Qt のいくつかのマルチスレッド実装

おすすめ

転載: blog.csdn.net/XCJandLL/article/details/125572670
おすすめ