Qt 的4种多线程实现详解

Qt 的4种多线程实现详解比如 如果在 UI 线程里面进行耗时操作 界面会不响应用户操作 Concurrent Map and Map Reduce

大家好,欢迎来到IT知识分享网。

为何需要多线程?

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; /* ... here is the expensive or blocking operation ... */ 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; /* ... 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); 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学习资料→「链接」

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种多线程实现详解

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/182932.html

(0)
上一篇 2025-07-10 13:00
下一篇 2025-07-10 13:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信