Qt 多线程的几种实现方式

这篇具有很好参考价值的文章主要介绍了Qt 多线程的几种实现方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Qt多线程的实现方式有:

1. 继承QThread类,重写run()方法

2. 使用moveToThread将一个继承QObject的子类移至线程,内部槽函数均在线程中执行

3. 使用QThreadPool,搭配QRunnable(线程池)

4. 使用QtConcurrent(线程池)

为什么要用线程池?

创建和销毁线程需要和OS交互,少量线程影响不大,但是线程数量太大,势必会影响性能,使用线程池可以减少这种开销。

一、继承QThread类,重写run()方法

缺点:

  1. 每次新建一个线程都需要继承QThread,实现一个新类,使用不太方便。
  2. 要自己进行资源管理,线程释放和删除。并且频繁的创建和释放会带来比较大的内存开销。
适用场景:QThread适用于那些常驻内存的任务。

 1 //mythread.h
 2 #ifndef MYTHREAD_H
 3 #define MYTHREAD_H
 4 
 5 #include <QThread>
 6 
 7 class MyThread : public QThread
 8 {
 9 public:
10     MyThread();
11     void stop();
12 
13 protected:
14     void run();
15 
16 private:
17     volatile bool stopped;
18 };
19 
20 #endif // MYTHREAD_H
 1 //mythread.cpp
 2 #include "mythread.h"
 3 #include <QDebug>
 4 #include <QString>
 5 
 6 MyThread::MyThread()
 7 {
 8     stopped = false;
 9 }
10 
11 
12 
13 void MyThread::stop()
14 {
15     stopped = true;
16 }
17 
18 
19 
20 void MyThread::run()
21 {
22     qreal i = 0;
23 
24     while( !stopped )
25     {
26         qDebug() << QString("in MyThread: %1").arg(i);
27         sleep(1);
28         i++;
29     }
30     stopped = false;
31 }
 1 //widget.h
 2 #ifndef WIDGET_H
 3 #define WIDGET_H
 4 
 5 #include <QWidget>
 6 #include "mythread.h"
 7 
 8 
 9 QT_BEGIN_NAMESPACE
10 namespace Ui { class Widget; }
11 QT_END_NAMESPACE
12 
13 class Widget : public QWidget
14 {
15     Q_OBJECT
16 
17 public:
18     Widget(QWidget *parent = nullptr);
19     ~Widget();
20 
21 private slots:
22     void on_startBut_clicked();
23 
24     void on_stopBut_clicked();
25 
26 private:
27     Ui::Widget *ui;
28     MyThread thread;
29 };
30 #endif // WIDGET_H
 1 //widget.cpp
 2 
 3 #include "widget.h"
 4 #include "ui_widget.h"
 5 
 6 Widget::Widget(QWidget *parent)
 7     : QWidget(parent)
 8     , ui(new Ui::Widget)
 9 {
10     ui->setupUi(this);
11     ui->startBut->setEnabled(true);
12     ui->stopBut->setEnabled(false);
13 }
14 
15 Widget::~Widget()
16 {
17     delete ui;
18 }
19 
20 
21 void Widget::on_startBut_clicked()
22 {
23     thread.start();
24     ui->startBut->setEnabled(false);
25     ui->stopBut->setEnabled(true);
26 }
27 
28 void Widget::on_stopBut_clicked()
29 {
30     if( thread.isRunning() )
31     {
32         thread.stop();
33         ui->startBut->setEnabled(true);
34         ui->stopBut->setEnabled(false);
35     }
36 }

qt创建多线程的方法,qt,ui,开发语言

qt创建多线程的方法,qt,ui,开发语言

qt创建多线程的方法,qt,ui,开发语言

二、使用moveToThread将一个继承QObject的子类移至线程

更加灵活,不需要继承QThread,不需要重写run方法,适用于复杂业务的实现。

注意,该业务类的不同槽函数均在同一个线程中执行。

 1 //worker.h
 2 #ifndef WORKER_H
 3 #define WORKER_H
 4 
 5 #include <QObject>
 6 
 7 class Worker : public QObject
 8 {
 9     Q_OBJECT
10 
11 public:
12     Worker();
13 
14     ~Worker();
15 
16 public slots:
17     void doWork();
18 
19     void another();
20 
21 signals:
22     void stopWork();
23 
24 };
25 
26 #endif // WORKER_H
 1 //worker.cpp
 2 #include "worker.h"
 3 #include <QDebug>
 4 #include <QThread>
 5 
 6 Worker::Worker()
 7 {
 8 
 9 }
10 
11 
12 Worker::~Worker()
13 {
14 
15 }
16 
17 
18 void Worker::doWork()
19 {
20     qDebug() << "current thread id is " << QThread::currentThreadId();
21     emit stopWork();
22 }
23 
24 
25 void Worker::another()
26 {
27     qDebug() << "another current thread id is " << QThread::currentThreadId();
28     //emit stopWork();
29 }
 1 //dialog.h
 2 #ifndef DIALOG_H
 3 #define DIALOG_H
 4 
 5 #include <QDialog>
 6 #include <QThread>
 7 #include "worker.h"
 8 
 9 QT_BEGIN_NAMESPACE
10 namespace Ui { class Dialog; }
11 QT_END_NAMESPACE
12 
13 class Dialog : public QDialog
14 {
15     Q_OBJECT
16 
17 public:
18     Dialog(QWidget *parent = nullptr);
19     ~Dialog();
20 
21 signals:
22     void startWork();
23     void startAnother();
24 
25 public slots:
26     void endThread();
27 
28 private:
29     Ui::Dialog *ui;
30     QThread *m_pThread;
31     Worker *m_pWorker;
32 };
33 #endif // DIALOG_H
 1 //dialog.cpp
 2 #include "dialog.h"
 3 #include "ui_dialog.h"
 4 #include <QDebug>
 5 
 6 Dialog::Dialog(QWidget *parent)
 7     : QDialog(parent)
 8     , ui(new Ui::Dialog)
 9 {
10     ui->setupUi(this);
11 
12     m_pThread = new QThread();
13     m_pWorker = new Worker();
14 
15     connect(this, &Dialog::startWork, m_pWorker, &Worker::doWork);
16     connect(this, &Dialog::startAnother, m_pWorker, &Worker::another);
17     connect(m_pWorker, &Worker::stopWork, this, &Dialog::endThread);
18     m_pWorker->moveToThread(m_pThread);
19     m_pThread->start();
20     emit startWork();
21     emit startAnother();
22 }
23 
24 Dialog::~Dialog()
25 {
26     delete ui;
27     delete m_pThread;
28     delete m_pWorker;
29 }
30 
31 
32 void Dialog::endThread()
33 {
34     qDebug() << "endThread";
35     m_pThread->quit();
36     m_pThread->wait();
37 }

qt创建多线程的方法,qt,ui,开发语言

不过我为什么要用界面类呢?搞不懂!

三、使用QThreadPool,搭配QRunnable

QRunnable常用接口:

  bool QRunnable::autoDelete() const;

  void QRunnable::setAutoDelete(bool autoDelete);

  • QRunnable 常用函数不多,主要设置其传到底给线程池后,是否需要自动析构;
  • 若该值为false,则需要程序员手动析构,要注意内存泄漏;

QThreadPool常用接口:

  void QThreadPool::start(QRunnable * runnable, int priority = 0);

  bool QThreadPool::tryStart(QRunnable * runnable);

  • start() 预定一个线程用于执行QRunnable接口,当预定的线程数量超出线程池的最大线程数后,QRunnable接口将会进入队列,等有空闲线程后,再执行;
  • priority指定优先级
  • tryStart()start() 的不同之处在于,当没有空闲线程后,不进入队列,返回false

业务类需要继承QRunnable,并且重写run()方法。注意,QRunnbale不是QObject的子类,可以发射信号,但用不了槽函数。

优点:无需手动释放资源,QThreadPool启动线程执行完成后会自动释放。
缺点:不能使用信号槽与外界通信。
适用场景:QRunnable适用于线程任务量比较大,需要频繁创建线程。QRunnable能有效减少内存开销

 1 //myrunnable.h
 2 #ifndef MYRUNNABLE_H
 3 #define MYRUNNABLE_H
 4 
 5 #include <QRunnable>
 6 #include <QString>
 7 
 8 
 9 class MyRunnable : public QRunnable
10 {
11 public:
12     MyRunnable(const QString szThreadName);
13     void run();
14 
15 private:
16     QString m_szThreadName;
17 };
18 
19 #endif // MYRUNNABLE_H
 1 //myrunnable.cpp
 2 #include "myrunnable.h"
 3 #include <QDebug>
 4 #include <QThread>
 5 
 6 MyRunnable::MyRunnable(const QString szThreadName) : m_szThreadName(szThreadName)
 7 {
 8 
 9 }
10 
11 
12 void MyRunnable::run()
13 {
14     qDebug() << "Start thread id : " << QThread::currentThreadId();
15     int iCount = 0;
16 
17     while (1)
18     {
19         if(iCount >= 10)
20         {
21             break;
22         }
23 
24         qDebug() << m_szThreadName << " count : " << iCount++;
25         QThread::msleep(500);
26     }
27 }
 1 //mian.cpp
 2 #include <QCoreApplication>
 3 #include "myrunnable.h"
 4 #include <QThreadPool>
 5 
 6 static QThreadPool* g_pThreadPool = NULL;
 7 
 8 int main(int argc, char *argv[])
 9 {
10     QCoreApplication a(argc, argv);
11 
12     MyRunnable* pRunnable1 = new MyRunnable("1# thread");
13     pRunnable1->setAutoDelete(true);
14 
15     MyRunnable* pRunnable2 = new MyRunnable("2# thread");
16     pRunnable2->setAutoDelete(true);
17 
18     g_pThreadPool = QThreadPool::globalInstance();
19 
20     g_pThreadPool->start(pRunnable1);
21     g_pThreadPool->start(pRunnable2);
22 
23     g_pThreadPool = NULL;
24 
25     return a.exec();
26 }

qt创建多线程的方法,qt,ui,开发语言

四、使用QtConcurrent

Concurrent是并发的意思,QtConcurrent是一个命名空间,提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展。

QtConcurrent::run能够方便快捷的将任务丢到子线程中去执行,无需继承任何类,也不需要重写函数,使用非常简单。

QtConcurrent常用接口:

  QFuture<T> QtConcurrent::run(Function function, ...)

  QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)

需要在pro文件中添加:

QT      += concurrent
 1 //main.cpp
 2 #include <QCoreApplication>
 3 #include <QThread>
 4 #include <QThreadPool>
 5 #include <QtConcurrent/QtConcurrent>
 6 #include <QDebug>
 7 #include <QFuture>
 8 
 9 static QThreadPool* g_pThreadPool = QThreadPool::globalInstance();
10 
11 class HELLO
12 {
13 public:
14     QString hello(QString szName)
15     {
16         qDebug() << "Hello " << szName << " from " << QThread::currentThreadId();
17         return szName;
18     }
19 
20     void run()
21     {
22         QFuture<QString> f3 = QtConcurrent::run(this, &HELLO::hello, QString("Lily"));
23         QFuture<QString> f4 = QtConcurrent::run(g_pThreadPool, this, &HELLO::hello, QString("Sam"));
24 
25         f3.waitForFinished();
26         f4.waitForFinished();
27 
28         qDebug() << "f3 : " << f3.result();
29         qDebug() << "f4 : " << f4.result();
30     }
31 };
32 
33 QString hello(QString szName)
34 {
35     qDebug() << "Hello " << szName << " from " << QThread::currentThreadId();
36     return szName;
37 }
38 
39 int main(int argc, char *argv[])
40 {
41     QCoreApplication a(argc, argv);
42 
43     QFuture<QString> f1 = QtConcurrent::run(hello, QString("Alice"));
44     QFuture<QString> f2 = QtConcurrent::run(g_pThreadPool, hello, QString("Bob"));
45 
46     f1.waitForFinished();
47     f2.waitForFinished();
48 
49     qDebug() << "f1 : " << f1.result();
50     qDebug() << "f2 : " << f2.result();
51 
52     HELLO h;
53     h.run();
54 
55     g_pThreadPool = NULL;
56 
57     return a.exec();
58 }

qt创建多线程的方法,qt,ui,开发语言文章来源地址https://www.toymoban.com/news/detail-558238.html

到了这里,关于Qt 多线程的几种实现方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt 播放音频文件的几种方式

    : Qt 、 QSound 、 QSoundEffect 、 QMediaPlayer 、 multimedia 这篇文章至少拖了有一两个月了,这不阳了,在家实在是难受的要死,无心处理工作的事情,那就写写博客吧,因为项目中需要用到播放音频的功能,CV了部分代码,这里就简单的扯扯我对 QSound 、 QSoundEffect 和 QMediaP

    2024年02月11日
    浏览(29)
  • qt初入门1:qt读文件的几种方式简单整理

    工作变动开始接触qt,涉及到qt读文件相关业务,简单整理一下qt读文件几种方式,后面发现有其他的再新增 测试demo的方式归纳汇总几种读qt文件的方法 : 1:获取文件源按钮,并打印获取到的相关文件名 2:使用qfile直接读文件,显示耗时时间 3:使用qdatastream读文件,显示耗

    2024年02月12日
    浏览(30)
  • 【昕宝爸爸小模块】浅谈之创建线程的几种方式

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 在Java中,共有

    2024年01月18日
    浏览(48)
  • Qt中正确的设置窗体的背景图片的几种方式

    原文链接:https://blog.csdn.net/yanche521/article/details/51017601 Qt中正确的设置窗体的背景图片的方法大致有两种,下面将逐个讲解: 使用stylesheet设置窗体的背景图片的时候,可以直接按照下图的操作去进行即可,如下图所示: 但是,需要注意的是: 1.在QWidget中这种方法是不行的,

    2024年02月05日
    浏览(36)
  • 线程间实现通信的几种方式

    线程间通信的模型有两种:共享内存和消息传递,下面介绍的都是围绕这两个来实现 有两个线程A和B,B线程向一个集合里面依次添加元素“abc”字符串,一共添加10次,当添加到第五次的时候,希望线程A能够收到线程B的通知,然后B线程执行相关的业务操作 Object类提供了线程

    2024年02月15日
    浏览(37)
  • 【Qt】qDebug() 输出16进制数的几种方法

    Qt qDebug() 输出16进制数字的几种方法整理:

    2024年04月28日
    浏览(25)
  • QT中信号与槽机制的介绍,以及信号与槽连接的几种方式

    功能:实现多个组件之间的相互通信,是QT引以为傲的核心机制 信号:就是信号函数,定义在类体的signals权限下,是一个不完整的函数,只有声明没有定义; 槽:就是槽函数,定义在类体的slots权限下,是一个完整的函数,既有声明也有定义,也可以当做普通函数被使用 无

    2024年02月10日
    浏览(33)
  • java 实现开启异步线程的几种方式

    在Java中,有多种方式可以实现异步线程以避免在主线程中执行耗时操作导致界面卡顿的问题。以下是几种常用的方式: 使用 Thread 类:可以使用 Thread 类来创建一个新的线程,并在其 run() 方法中执行耗时操作。例如: 使用 Runnable 接口:可以通过实现 Runnable 接口并在其中实现

    2024年02月14日
    浏览(33)
  • C#针对VS线程间操作提示:程间操作无效: 从不是创建控件“”的线程访问它的几种解决方法

    转载请标明出处:Python Excellent的博客 此为最基础方法 (入门级) 运行效果如图所示 * 先在按钮事件中创建一个Test1()线程 * 在测试1中有两种方法可以访问窗体线程(首推荐) public SynchronizationContext UiContext //第一步全局声明 UiContext = SynchronizationContext.Current; //第二部在public For

    2024年02月08日
    浏览(34)
  • QT创建线程的方法:一步步教你创建和启动线程

    目录 线程概念及官方文档  一、线程的创建:继承方式 二、线程的创建:QObject 对象(moveToThread) 2.1 创建任务类 2.2 添加线程启动(定时器启动) 2.3 添加线程启动(start信号启动) 三、线程类的基本接口和使用 3.1启动 和终止线程 3.2 线程延迟 3.3 线程同步及通信方式 3.4

    2024年02月13日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包