QT 学習 - スレッド

場合によっては、アプリケーションはより複雑なロジックを処理する必要があります。処理するスレッドが 1 つしかない場合、ウィンドウがフリーズし、ユーザーの関連操作を処理できなくなります。この場合は、マルチスレッドが必要です。

Qt でのマルチスレッドの使用に注意してください。

  1. Qt のデフォルトのスレッドはウィンドウ スレッド (メイン スレッド) ですウィンドウ イベントの処理やウィンドウ コントロール データの更新を担当します
  2. 子スレッドはバックグラウンドでビジネス ロジックを担当しますが、子スレッドはウィンドウ オブジェクトに対して操作を行うことはできず、これらの操作はウィンドウ スレッドに渡されます。
  3. メインスレッドと子スレッドの間でデータが転送される場合は、シグナルスロットメカニズムを使用する必要があります。

QT は、スレッドによって使用される必要がある QThread クラスを使用します。QThreadスレッド クラスで使用される一般的なメソッドは次のとおりです。

QThread (QObject *= nullptr)
バーチャル ~Qスレッド()
QAbstractEventDispatcher * eventDispatcher ()const
空所

終了(int returnCode = 0)

スレッドを終了するワーカー関数

ブール

isFinished () const

スレッド内のタスクが処理されたかどうかを判断する

ブール

isInterruptionRequested () const

ブール

isRunning () const

スレッド内のタスクがタスクを実行しているかどうかを判断します。

整数

ループレベル()const

スレッドの現在のイベント ループ レベルを返します。

Qスレッド::優先度

優先順位() 定数

現在のスレッドの優先順位を取得します

空所

リクエスト中断()

この関数を使用すると、長時間実行されるタスクを完全に中断可能にすることができます。この関数によって返された値を検査または操作しないことは安全ですが、長時間実行される関数では定期的に検査または操作することをお勧めします。オーバーヘッドを低く抑えるために、あまり頻繁に呼び出さないように注意してください。

空所

setEventDispatcher (QAbstractEventDispatcher * eventsDispatcher )

空所

setPriority (QThread::Priority優先順位)

現在のスレッドの優先順位を設定する

空所

setStackSize (uint stackSize )

単位

stackSize () 定数

ブール

wait (QDeadlineTimer期限= QDeadlineTimer(QDeadlineTimer::Forever))

呼び出し元のスレッドが関数を終了した後、現在のタスクが完了していない可能性があるため、スレッドはすぐには終了しません。

ブール

待機(符号なしの長時間)

 

パブリックスロット

空所

やめます()

スレッドのイベント ループに戻りコード 0 (成功) で終了するように指示します。QThread::exit(0) を呼び出すことと同じです。
スレッドにイベント ループがない場合、この関数は何も行いません。

空所

start (QThread::Priority優先順位= InheritPriority)

run() を呼び出して実行スレッドを開始します。オペレーティング システムは、優先度パラメータに従ってスレッドをスケジュールします。スレッドがすでに実行されている場合、この関数は何も行いません。

空所

終了()

スレッドの実行を終了します。オペレーティング システムのスケジューリング ポリシーによっては、スレッドがすぐに終了する場合とそうでない場合があります。安全のために、terminate() の後に QThread::wait() を使用してください。

信号

空所 終わった()
空所 始めました()

静的パブリックメンバー

Qスレッド *

create ( 関数 && f , 引数 & & ... args )

関数オブジェクトfとパラメーターを実行する新しいQThreadを作成します。

Qスレッド * create (関数 && f )
Qスレッド * 現在のスレッド()
Qt::ハンドル currentThreadId ()
整数 IdealThreadCount ()
空所 msleep (符号なしの長いミリ秒)
空所

sleep(unsigned long secs)

强制当前线程休眠秒。

void usleep(unsigned long usecs)
void

yieldCurrentThread()

将当前线程的执行转换为另一个可运行线程(如果有)。请注意,操作系统决定切换到哪个线程。

Protected Functions

int

exec()

进入事件循环并等待直到exit(),返回传递给exit().返回的值为0,如果exit()通过调用exit().

virtual void

run()

线程的起点。在调用start()之后,新创建的线程调用此函数。默认实现只是调用exec()。
您可以重新实现此函数以促进高级线程管理。从此方法返回将结束线程的执行。

Static Protected Members

void

setTerminationEnabled(bool enabled = true)

属性启用或禁用当前线程的终止enabled 参数。线程必须由QThread.

什么时候enabled 为false,则禁用终止。未来呼叫QThread::terminate()将立即返回而不起作用。相反,终止被推迟,直到启用终止。

优先级:

  1. QThread::IdlePriority --> 最低的优先级
  2. QThread::LowestPriority
  3. QThread::LowPriority
  4. QThread::NormalPriority
  5. QThread::HighPriority
  6. QThread::HighestPriority
  7. QThread::TimeCriticalPriority
  8. QThread::InheritPriority --> 最高的优先级, 默认是这个

线程创建1

1.创建一个线程类的子对象,继承QThread

2.重写父类的run()方法,在该函数内部编写子线程要处理的具体业务流程

mythread.hpp

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QObject>

class mythread : public QThread
{
    Q_OBJECT
public:
    explicit mythread(QObject *parent = nullptr);
protected:
    void run();
signals:
    void isDone();
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QDebug>
mythread::mythread(QObject *parent) : QThread(parent)
{

}
void mythread::run(){
    qDebug()<<"线程启动";
    QThread::sleep(5);
    emit isDone();
}

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QTimer>
#include <QWidget>
#include <mythread.h>
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui { class myWidget; }
QT_END_NAMESPACE

class myWidget : public QWidget
{
    Q_OBJECT
private:
    mythread *thread;
    QTimer * timer;
public:
    myWidget(QWidget *parent = nullptr);
    ~myWidget();
    void dealTimeOut();
    void dealDone();
    void stopThread();
private slots:
    void on_pushButton_clicked();

private:
    Ui::myWidget *ui;
};
#endif // MYWIDGET_H

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>
#include <QDebug>
myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
    timer =new QTimer(this);
    thread = new mythread(this);
//    定时器启动自动产生Timeout指令
    connect(timer,&QTimer::timeout,this,&myWidget::dealTimeOut);
    connect(thread,&mythread::isDone,this,&myWidget::dealDone);
    connect(this,&myWidget::destroyed,this,&myWidget::stopThread);
    ui->setupUi(this);
}
void myWidget::dealTimeOut(){
    static int i = 0;
    i++;
    ui->lcdNumber->display(i);
}
myWidget::~myWidget()
{
    delete ui;
}
void myWidget::stopThread(){
       thread->quit();
       thread->wait();
}

void myWidget::on_pushButton_clicked()
{
    if(timer->isActive()==false){
        timer->start(500);
         thread->start();
    }
//    QThread::sleep(5);

//    qDebug()<<"定时器结束";
}
void myWidget::dealDone(){
    qDebug()<<"it is over";
    timer->stop();

}

线程创建2

class Worker : public QObject //继承自QObject
{
    Q_OBJECT
 
public slots:
    void doWork(const QString &parameter) {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
 
signals:
    void resultReady(const QString &result);
};
 
class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;//创建一个线程
public:
    Controller() {
        Worker *worker = new Worker;//创建一个工作对象
        worker->moveToThread(&workerThread);//移动到线程种执行
        //当线程执行完成后,销毁work对象
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(this, &Controller::operate, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();//开启线程
    }
    ~Controller() {
        workerThread.quit();//关闭线程
        workerThread.wait();//堵塞线程
    }
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);

线程创建3

创建

QRunnable是所有可执行对象的基类继承QRunnable类后重写其中的run()函数,即可实现线程开发。虽然基本步骤和QThread的做法一致。但是,QRunnable不能自己运行,而是必须借助于QThreadPool类运行

#ifndef THREAD02_H
#define THREAD02_H
 
#include <QRunnable>
 
class Thread02 : public QRunnable
{
public:
    Thread02();
    ~Thread02();
    void run() override;
};
 
#endif // THREAD02_H

#include "thread02.h"
#include <QThread>
 
#include <iostream>
 
using namespace std;
Thread02::Thread02()
{
    cout<< "Thread01 construct fun" << QThread::currentThread() << endl;
}
 
Thread02::~Thread02()
{
      cout<< "Thread01 destructor fun" << QThread::currentThread() << endl;
}
 
void Thread02::run()
{
     cout<< "Thread02 construct fun" << QThread::currentThread() << endl;
}

启动

线程的启动方法如下:

#include <QCoreApplication>

#include "thread02.h"
#include <iostream>
#include <QThreadPool>
using namespace std;
 
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    cout<< "main thread" << QThread::currentThread() << endl;
 
   /* Thread01 th;
    th.start();*/
 
   Thread02 *th = new Thread02();
   QThreadPool::globalInstance()->start(th);
 
    cout<< "main thread end" << endl;
 
    return a.exec();
}

QThreadPool线程池

QThreadPool管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问。

要使用其中一个QThreadPool线程,请子类化QRunnable并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()。

class HelloWorldTask : public QRunnable
{
    void run() override
    {
        qDebug() << "Hello world from thread" << QThread::currentThread();
    }
};

HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);

Properties

  • activeThreadCount : const int   此属性表示线程池中的活动线程数
  • expiryTimeout : int 在expiryTimeout毫秒内未使用的线程被认为已过期并将退出。此类线程将根据需要重新启动。默认的expiryTimeout为30000毫秒(30秒)
  • maxThreadCount : int 此属性表示线程池使用的最大线程数。
  • stackSize : uint 此属性包含线程池工作线程的堆栈大小。

Public Functions公共职能

QThreadPool(QObject *parent = nullptr)
virtual ~QThreadPool()
int

activeThreadCount() const

此属性表示线程池中的活动线程数

void

clear()

从队列中移除尚未启动的可运行对象。runnable->autoDelete()返回true的runnables被删除。

bool

contains(const QThread *thread) const

如果thread是由这个线程池管理的线程,则返回true

int

expiryTimeout() const

int

maxThreadCount() const

此属性表示线程池使用的最大线程数

void

releaseThread()

释放先前通过调用reserveThread()保留的线程。

void

reserveThread()

保留一个线程,忽略activeThreadCount()和maxThreadCount()。

void setExpiryTimeout(int expiryTimeout)
void

setMaxThreadCount(int maxThreadCount)

设置最大线程数量

void

setStackSize(uint stackSize)

uint

stackSize () 定数

このプロパティには、スレッド プール ワーカー スレッドのスタック サイズが含まれます。

空所

start (QRunnable * runnable、int  priority  = 0)

操作をキューに入力します。開始は必ずしもすぐに開始されるわけではなく、キューに挿入されるだけであり、キューに追加されたときに実行が開始されることに注意してください。QRunnable で渡す必要があります

空所

start (std::function<void ()>  functionToRun、int  priority  = 0)

ブール

tryStart (QRunnable * runnable )

を始めてみる

ブール tryStart (std::function<void ()>  functionToRun )
ブール

tryTake (QRunnable * runnable )

キュー内の QRunnable を削除し、現在の QRunnable が開始されていない場合は成功を返します。

ブール

waitForDone (int ミリ秒 = -1)

すべてのスレッドが実行を終了して終了するまで待機します。パラメータは待機時間です。 -1 は、最後のスレッドが終了するまで待機することを意味します。

mythread.h 

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QRunnable>
#include <QObject>
#include <QDebug>
#include <QReadWriteLock>
#include <QTime>
#include <QSemaphore>
 
class mythread : public QObject, public QRunnable
{
        Q_OBJECT
public:
    mythread();
 
 
    //QThread的虚函数
    //线程处理函数
    //不能直接调用,通过start()间接调用
    void run();
 
signals:
    void isDone(int);   //处理完成信号
    void mySignal();    //注意!要使用信号,采用QObejct 和 QRunnable多继承,记得QObject要放在前面
 
public slots:
    //接收主线程的消息
    void recMegFromMain(QString);
};
 
class mythread1 : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
 
};
 
class mythread2  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
 
 
class mythread3  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
 
class mythread4  : public QObject, public QRunnable
{
    Q_OBJECT
public:
 
    void run();
};
#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QMutex>
#include <QRandomGenerator>
#include <QWaitCondition>
#include <QThread>
/*
如果乱码就加上QStringLiteral();
#pragma execution_character_set("GB2312")
*/
mythread::mythread()
{
 
}
void mythread::run()
{
 
 
    for(int i=0;i<10;i++){
        //QThread::sleep(2);
        qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() << QStringLiteral( " 线程1打印数据:") <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
void mythread::recMegFromMain(QString str)
{
    qDebug()<< "子线程接收到" <<str;
}
 
void mythread1::run()
{
 
    qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() ;
    for(int i=10;i<20;i++){
        QThread::sleep(2);
        qDebug()<< "线程2打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread2::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=20;i<30;i++){
        QThread::sleep(2);
        qDebug()<< "线程3打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread3::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=30;i<40;i++){
        QThread::sleep(2);
        qDebug()<< "线程4打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}
 
void mythread4::run()
{
 
    qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
    for(int i=40;i<50;i++){
        QThread::sleep(2);
        qDebug()<< "线程5打印数据:" <<QString::number(i);
    }
    //emit isDone(1);  //发送完成信号
}

メインウィンドウ.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "mythread.h"
#include <QDebug>
#include <QMessageBox>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
 
    void dealDone();   //线程槽函数
 
    void mySlot();
 
    void receiveMsgFromThread(int);
 
    void sengMsgToThreadBtn();
private:
    Ui::MainWindow *ui;
 
    QThreadPool pool;
 
    mythread* task = new mythread();
    mythread1* task1 = new mythread1();
    mythread2* task2 = new mythread2();
    mythread3* task3 = new mythread3();
    mythread4* task4 = new mythread4();
signals:
    //给子线程发消息
    void sengMsgToThread(QString);
private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
    void on_pushButton_3_clicked();
    void on_pushButton_4_clicked();
    void on_pushButton_5_clicked();
    void on_pushButton_6_clicked();
    void on_pushButton_7_clicked();
    void on_pushButton_8_clicked();
};
#endif // MAINWINDOW_H

メインウィンドウ.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
 
#include <QReadWriteLock>
 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    //设置最大线程数为3的一个线程池
    pool.setMaxThreadCount(5);
 
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::sengMsgToThreadBtn()
{
    emit sengMsgToThread("hello");
}
// 定义槽函数 mySlot()
void MainWindow::mySlot()
{
    QMessageBox::about(this,"Tsignal", "响应线程中的mySlot函数");
}
//接收线程函数
void MainWindow::receiveMsgFromThread(int i)
{
    QString str = QString::number(i);
    qDebug()<<str;
}
void MainWindow::dealDone()
{
    ui->label->setText("线程停止");
    //停止线程
 
}
 
void MainWindow::on_pushButton_clicked()
{
 
    //QThread::sleep(1);
    //pool.waitForDone();           //等待任务结束
    on_pushButton_4_clicked();
    on_pushButton_5_clicked();
    on_pushButton_6_clicked();
    on_pushButton_7_clicked();
    on_pushButton_8_clicked();
 
    //启动线程,处理数据
    ui->label->setText("start");
 
}
 
void MainWindow::on_pushButton_2_clicked()
{
    //pool.releaseThread();
    //停止线程
    //dealDone();
    //sengMsgToThreadBtn();
}
 
void MainWindow::on_pushButton_3_clicked()
{
    qDebug() <<pool.activeThreadCount();
    //sengMsgToThreadBtn();
}
 
void MainWindow::on_pushButton_4_clicked()
{
    pool.start(task);             //任务放进线程池
    task->setAutoDelete(false);
}
 
void MainWindow::on_pushButton_5_clicked()
{
    pool.start(task);             //任务放进线程池
    task->setAutoDelete(false);
    /*
    pool.start(task1);
    task1->setAutoDelete(false);
    */
}
 
void MainWindow::on_pushButton_6_clicked()
{
    pool.start(task);             //任务放进线程池
 
    //pool.start(task2);
}
 
void MainWindow::on_pushButton_7_clicked()
{
    pool.start(task);             //任务放进线程池
    //pool.start(task3);
}
 
void MainWindow::on_pushButton_8_clicked()
{
    pool.start(task);             //任务放进线程池
    //pool.start(task4);
}

おすすめ

転載: blog.csdn.net/qq_44632658/article/details/131637506