首页 / 财经 / 宏观经济 / 正文

qt多线程(Qt 的4种多线程实现详解)

放大字体  缩小字体 来源:流产后的注意事项 2026-04-17 17:32  浏览次数:9

为何需要多线程?

1、进行耗时操作时,可以处理用户的其他输入输出。比如,如果在UI线程里面进行耗时操作,界面会不响应用户操作。

2、提升程序性能。现在的电脑一般都是多核CPU,多线程并行处理事务,可以大大提升程序的性能。

针对第一点,为我们定位界面不响应问题指明了一个方向;针对第二点,为我们提升软件处理效率指明了一个方向。

那么,基于Qt开发的应用程序,如何实现多线程呢?

目录

1、继承QThread,重载run函数。

2、继承QObject,调用void QObject::moveToThread(QThread *targetThread)。

3、QThreadPool and QRunnabl。

4、Qt Concurrent。

5、测试代码

使用多线程之前,特别需要注意的一点是:

非UI线程不能操作UI对象(从QWidget直接或间接派生的窗口对象)

1、继承QThread,重载run函数。

这种方法比较适用于处理耗时很长的业务。示例代码如下:

 class WorkerThread : public QThread  {      Q_OBJECT      void run() override {          QString result;                    emit resultReady(result);      }  signals:      void resultReady(const QString &s);  };   void MyObject::startWorkInAThread()  {      WorkerThread *workerThread = new WorkerThread(this);      connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);      workerThread->start();  }

需要注意以下几点:

1)run函数在新线程中执行,run函数执行结束,线程结束。

2)WorkerThread实例化的对象属于创建他的线程,而不是run函数所在线程。

3)WorkerThread没有事件循环,除非在run()函数中调用exec();

4)队列连接到WorkerThread的slot函数,slot函数在创建WorkerThread对象的线程中执行。

5)直接调用WorkerThread的方法,该方法的执行线程为调用处的线程。


2、继承QObject,调用void QObject::moveToThread(QThread *targetThread)。

这种方法适用于在一个类中处理多个耗时任务,且这个些任务不会并行执行的情况。示例代码如下:

  class Worker : public QObject  {      Q_OBJECT   public slots:      void doWork(const QString ¶meter) {          QString result;                    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);          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 &);  };

需要注意以下几点:

1)调用moveToThread函数的对象不能设置父对象。

2)Worker类中的槽函数可以跟任意线程的任意信号建立连接,队列连接时,在新线程中执行。

3)直接调用Worker类中的函数,在调用线程内执行。

4)同时发送多个与Worker类中槽函数连接的信号,槽函数依次执行。

领Qt学习资料→ntent="mp" data-source="outerlink" href="http://docs.qq.com/doc/DQlVKZG14U1hCQXJu" rel="noopener noreferrer noopener noreferrer" target="_blank">「链接」

3、QThreadPool and QRunnabl。

我们都知道频繁创建和销毁线程会带来较大的性能开销,影响程序执行效率。Qt的线程池技术,给了我们一个解决这个问题的有效方法。示例代码如下:

  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);

注意:

1)默认情况下,run函数执行完,hello对象会被线程池自动删除。可以使用setAutoDelete函数设置。

2)QThreadPool::start()多次启动设置为autoDelete的QRunnable对象,可能导致崩溃。

4、Qt Concurrent。

QtConcurrent提供了高级api,使编写多线程程序时,不需要使用诸如互斥锁、读写锁、等待条件或信号量等低级线程安全类。具体用法,我们下回分解。传送门:Qt Concurrent 线程使用详解

Concurrent Run

 extern void aFunction(); QFuture<void> future = QtConcurrent::run(aFunction); 

Concurrent Map and Map-Reduce

  QList<QImage> images = ...;  // Each call blocks until the entire operation is finished.  QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);  QtConcurrent::blockingMap(images, scale);  QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

Concurrent Filter and Filter-Reduce

 QStringList strings = ...;  // each call blocks until the entire operation is finished  QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strings, allLowerCase);  QtConcurrent::blockingFilter(strings, allLowerCase);  QSet<QString> dictionary = QtConcurrent::blockingFilteredReduced(strings, allLowerCase, addToDictionary);

5、测试代码

main.cpp

#include "qtthreaddemo.h"#include <QtWidgets/QApplication>#include <QDebug>#include <QThread> int main(int argc, char *argv[]){    QApplication a(argc, argv);    qDebug() << "Main Thread Id:" << QThread::currentThreadId();    QtThreadDemo w;    w.show();    return a.exec();}

qtthreaddemo.h

#pragma once #include <QtWidgets/QWidget>#include "ui_qtthreaddemo.h" class WorkerThread1;class WorkerThread2; class QtThreadDemo : public QWidget{    Q_OBJECT public:    QtThreadDemo(QWidget *parent = Q_NULLPTR);private slots:    void on_btnCreateThread1_clicked();    void on_btnSlotFun_clicked();    void on_btnCreateThread2_clicked();    void on_btnTestOrders_clicked();    void on_btnRunnableThread_clicked();    void workerThreadEnd();signals:    void run_slot();private:    Ui::QtThreadDemoClass ui;    WorkerThread1 *m_pThread1 = nullptr;    WorkerThread2 *m_pThread2 = nullptr;};

qtthreaddemo.cpp

#include "qtthreaddemo.h"#include "workerthread1.h"#include "workerthread2.h"#include "runnablethread.h"#include <QDebug>#include <QThreadPool> QtThreadDemo::QtThreadDemo(QWidget *parent)    : QWidget(parent){    ui.setupUi(this);} void QtThreadDemo::on_btnCreateThread1_clicked(){    qDebug() << "btnCreateThread clicked Thread Id:" << QThread::currentThreadId();    m_pThread1 = new WorkerThread1(this);    connect(this, SIGNAL(run_slot()), m_pThread1, SLOT(doJob()), Qt::QueuedConnection);    connect(m_pThread1, SIGNAL(finished()), this, SLOT(workerThreadEnd()));    m_pThread1->start();} void QtThreadDemo::on_btnSlotFun_clicked(){    qDebug() << "btnSlotFun clicked Thread Id:" << QThread::currentThreadId();    emit run_slot();} void QtThreadDemo::on_btnCreateThread2_clicked(){    qDebug() << "btnCreateThread2 clicked";    if (m_pThread2 == nullptr)    {        m_pThread2 = new WorkerThread2(nullptr);    }    m_pThread2->doJob();} void QtThreadDemo::on_btnTestOrders_clicked(){    qDebug() << "btnTestOrders clicked";    if (m_pThread2 == nullptr)    {        m_pThread2 = new WorkerThread2(nullptr);    }    m_pThread2->testOrder();} void QtThreadDemo::on_btnRunnableThread_clicked(){    qDebug() << "btnRunnableThread clicked";    RunnableThread *pThread = new RunnableThread;    QThreadPool::globalInstance()->tryStart(pThread);    QThread::msleep(2000);    //QThreadPool::globalInstance()->tryStart(pThread);   //会发生异常} void QtThreadDemo::workerThreadEnd(){    qDebug() << "Worker Thread Ended!";}

workthread1.h

#pragma once #include <QThread> class WorkerThread1 : public QThread{    Q_OBJECT public:    WorkerThread1(QObject *parent);    ~WorkerThread1();    static void publicFun();protected:    void run(); private slots:    void doJob();};

workerthread1.cpp

#include "workerthread1.h"#include <QDebug> WorkerThread1::WorkerThread1(QObject *parent)    : QThread(parent){    qDebug() << "WorkerThread1 Object Thread Id:" << QThread::currentThreadId();} WorkerThread1::~WorkerThread1(){} void WorkerThread1::publicFun(){    qDebug() << "WorkerThread1::publicFun Thread Id:" << QThread::currentThreadId();} void WorkerThread1::run(){    qDebug() << "WorkerThread1 Create Thread Id:" << QThread::currentThreadId();} void WorkerThread1::doJob(){    qDebug() << "WorkerThread1 Slot-doJob Thread Id:" << QThread::currentThreadId();}

workerthread2.h

#pragma once #include <QObject>class QThread; class WorkerThread2 : public QObject{    Q_OBJECT public:    WorkerThread2(QObject *parent);    ~WorkerThread2();    void doJob();    void testOrder(); private slots:    void onDoJob();    void onOrder1();    void onOrder2();    void onOrder3(); signals:    void sig_do_job();    void sig_order1();    void sig_order2();    void sig_order3();private:    QThread *m_pThread;};

workerthread2.cpp

#include "workerthread2.h"#include <QThread>#include <QDebug>#include "workerthread1.h" WorkerThread2::WorkerThread2(QObject *parent)    : QObject(parent){    m_pThread = new QThread;    moveToThread(m_pThread);    m_pThread->start();     connect(this, SIGNAL(sig_do_job()), this, SLOT(onDoJob()), Qt::QueuedConnection);    connect(this, SIGNAL(sig_order1()), this, SLOT(onOrder1()), Qt::QueuedConnection);    connect(this, SIGNAL(sig_order2()), this, SLOT(onOrder2()), Qt::QueuedConnection);    connect(this, SIGNAL(sig_order3()), this, SLOT(onOrder3()), Qt::QueuedConnection);} WorkerThread2::~WorkerThread2(){} void WorkerThread2::doJob(){    qDebug() << "WorkerThread2::doJob thread id:" << QThread::currentThreadId();    emit sig_do_job();} void WorkerThread2::testOrder(){    emit sig_order1();    emit sig_order2();    emit sig_order3();} void WorkerThread2::onDoJob(){    qDebug() << "WorkerThread2::onDoJob thread id:" << QThread::currentThreadId();    WorkerThread1::publicFun();} void WorkerThread2::onOrder1(){    qDebug() << "WorkerThread2::onOrder1 begin";    QThread::msleep(1000);    qDebug() << "WorkerThread2::onOrder1 end";} void WorkerThread2::onOrder2(){    qDebug() << "WorkerThread2::onOrder2 begin";    QThread::msleep(1000);    qDebug() << "WorkerThread2::onOrder2 end";} void WorkerThread2::onOrder3(){    qDebug() << "WorkerThread2::onOrder3 begin";    QThread::msleep(1000);    qDebug() << "WorkerThread2::onOrder3 end";}

runnablethread.h

#pragma once #include <QRunnable> class RunnableThread : public QRunnable{public:    RunnableThread();    ~RunnableThread();    void run();};

runnablethread.cpp

#include "runnablethread.h"#include <QDebug>#include <QThread> RunnableThread::RunnableThread(){} RunnableThread::~RunnableThread(){} void RunnableThread::run(){    qDebug() << "RunnableThread::run Thread Id:" << QThread::currentThreadId();}

运行结果:

Qt 的4种多线程实现详解nerror="javascript:errorimg.call(this);">

打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心