Qt 多线程的几种实现方式

article/2025/10/27 19:43:18

Qt多线程的实现方式有:

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

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

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

4. 使用QtConcurrent(线程池)

为什么要用线程池?

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

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

缺点:

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

 1 //mythread.h2 #ifndef MYTHREAD_H3 #define MYTHREAD_H4 5 #include <QThread>6 7 class MyThread : public QThread8 {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.cpp2 #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.h2 #ifndef WIDGET_H3 #define WIDGET_H4 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.cpp2 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 }

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

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

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

 1 //worker.h2 #ifndef WORKER_H3 #define WORKER_H4 5 #include <QObject>6 7 class Worker : public QObject8 {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.cpp2 #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.h2 #ifndef DIALOG_H3 #define DIALOG_H4 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.cpp2 #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 }

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

三、使用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.h2 #ifndef MYRUNNABLE_H3 #define MYRUNNABLE_H4 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.cpp2 #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.cpp2 #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 }

四、使用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.cpp2 #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 }


http://chatgpt.dhexx.cn/article/HWlhInXN.shtml

相关文章

QT中的多线程

目录 1、QThread介绍 1.2、继承Qthread类 1.2.1、得到线程id 1.2.2、让线程一直执行 1.2.3、线程退出 1.2.4、​​​​​​​connect的第五个参数 1.2.5、线程锁 QMutex ​​​​​​​ 1、QThread介绍 QThread类提供了一个与平台无关的管理线程的方法。一个QThread对…

faild to create process解决办法

win7下运行pip时报faild to create process的解决办法&#xff1a; 1.找到python.exe文件&#xff0c;复制其文件路径。如下图&#xff0c;python.exe路径为D:\interpreter\python.exe。 2.找到pip-script.py文件&#xff0c;打开。将步骤1中复制的路径粘贴在第一行&#xff0…

CreateProcess error=2, 系统找不到指定的文件 解决方法

CreateProcess error2, 系统找不到指定的文件 解决方法 一般这是由于ndk缺少文件引起的 解决方法1&#xff1a; 在项目根目录下的local.properties文件中加cmd后缀 方法二下载16b的版本替换原来的ndk-bundle目录&#xff0c;默认在C:\Users\用户名\AppData\Local\Android\S…

SQL SERVER 2008 执行xp_cmdshell的过程中出错,调用createprocess失败,错误代码 5 解决方案

1、进入 控制面板----管理工具------本地安全策略 点击 本地策略--------安全选项 把“网络安全:LAN管理器身份验证级别”双击打开&#xff0c;选择“发送 LM 和 NTLM 响应”&#xff08;原来是“没有定义”&#xff09;。确认后&#xff0c;重新启动服务器&#xff0c;该问题…

runnerw.exe: CreateProcess failed with error 5:

在idea配置Git时遇到这个问题&#xff1a; 后来发现是我路径设置错了&#xff1a; 解决方案 修改设置里的路径即可&#xff08;Setings-Version Control-Git&#xff09;

Qt creater出现“启动程序失败,路径或者权限错误”或“The process could not be started!”解决方法

Qt creater出现“启动程序失败&#xff0c;路径或者权限错误”或“The process could not be started&#xff01;”解决方法 错误示例 远古版本的QTCreator在编译程序时没问题&#xff0c;在运行程序时会提示“The process could not be started&#xff01;" 较新版本…

failed to create process.

由于python-2.7是先出来&#xff0c;但是官方只更新到2020年1月1日&#xff1b;而python-3.6与python-2.7有一定的差别&#xff0c;会同时在电脑上安装这两个版本的python&#xff0c;为了能更好的调用python不同的版本&#xff0c;会设定一个执行时使用python2.exe&#xff0c…

CreateProcessAsUser

该CreateProcessAsUser函数创建一个新的进程及其主线程。新进程然后执行指定的可执行文件。该CreateProcessAsUser功能类似的CreateProcess函数&#xff0c;除了新进程运行在由hToken参数表示的用户的安全上下文中。默认情况下&#xff0c;新进程是非交互式的&#xff0c;即它运…

生成了文件却还是报错 Error:CreateProcess failed

想起来&#xff0c;以前用keil编译器的时候&#xff0c;也出现过这样的问题&#xff1a; 第一眼都是看到了“1 Error(s)”&#xff0c;就下意识认为自己程序出错了&#xff0c;找了半天没找到。 后来多看了一眼&#xff0c;发现完全这个错误其实可以完全不用理会&#xff0c;因…

【Error】Error running process: CreateProcess failed. Code 2

重新安装了pycham发现在pycharm里打不开控制台窗口了 解决办法&#xff1a; 在file -->setting --> Tools --> Terminal里 把Shell path 从 powershell.exe 改为 cmd.exe

Cannot run program “svn“ (in directory “D:xxxx“): CreateProcess error=2, 系统找不到指定的文件。报错解决方法

目录 一、报错内容 二 、原因 三、解决方法 一、报错内容 Cannot run program "svn" (in directory "xxxx"): CreateProcess error2, 系统找不到指定的文件 二 、原因 TortoiseSVN安装的时候没有安装command命令&#xff0c;不能通过命令执行版本管理…

CreateProcess error=5, 拒绝访问

一、情景再现 在一个Java项目中引入一个Python执行脚本&#xff0c;运行项目时报错&#xff1a; 二、问题分析 查看代码调用了源码中的exec&#xff08;&#xff09;方法 在java中&#xff0c;RunTime.getRuntime().exec()实现了调用服务器命令脚本来执行功能需要。也就是说…

failed to create process 的解决方式

网上大多数都是说python.exe移动了位置&#xff0c;导致你本来环境变量中配置的scripts中的python.exe找不到位置。 你需要修改scripts中的pip.exe中的python路径 如 当然这是其中一种可能性&#xff0c; 也有可能是由于你自己配置的环境变量产生了冲突 在windows的系统环境…

CreateProcess 创建进程失败原因调查

使用 CreateProcess 函数创建进程&#xff08;调用外部程序&#xff09;算是很常用的操作了&#xff0c;最近在工作中却遇到一个少见的怪现象&#xff0c;经常使用的一段代码&#xff08;调用外部程序并等待其结束&#xff0c;主要就使用了 CreateProcess 函数&#xff09;&…

jsp页面报org.apache.jasper.JasperException错误的一种解决方法

最近idea搭建ssm项目jsp页面出现如下问题 解决办法如下&#xff1a; 把 <% taglib uri“http://java.sun.com/jstl/core” prefix“c” %> 改成 <% taglib uri“http://java.sun.com/jstl/core_rt” prefix“c” %>

报org.apache.jasper.JasperException错误的一种解决方法

最近遇到的一个问题 把 <% taglib uri"http://java.sun.com/jstl/core" prefix"c" %> 改成 <% taglib uri"http://java.sun.com/jstl/core_rt" prefix"c" %> 这只是一种方法&#xff0c;如果解决不了&#xff0c;我…

org.apache.jasper.JasperException: java.lang.ClassNotFoundException解决办法

一、运行项目出错截图 报错找不到jsp文件&#xff0c;此时修改一下访问路径&#xff0c;会报如下错误: 二、解决java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/ConditionalTagSupport的方法&#xff1a; 1.缺少了相应的jar包&#xff1a; jstl-1.2standard…

org.apache.jasper.JasperException:解决办法!

org.apache.jasper.JasperException: The absolute uri: http://itcast.cn/common/ cannot be resolved in either web.xml or the jar files deployed with this application解决办法 今天在完成SSM框架整合的时候&#xff0c;使用eclipse在tomcat运行项目没提示任何问题&…

org.apache.jasper.JasperException: 无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/jstl/

问题如下&#xff1a; lib包下配置 jsp页面的导入一切正常&#xff0c;没有提示任何错误 网上也查了好多结果&#xff0c;最后发现修改tomcat中的conf/catalina.properties文件&#xff0c; tomcat.util.scan.DefaultJarScanner.jarsToSkip*.jar 改为&#xff1a; tomcat.ut…

javaweb项目报错:org.apache.jasper.JasperException: 无法为JSP编译类

执行相应的跳转页面&#xff0c;出现了报错&#xff1a; HTTP状态 500 - 内部服务器错误 org.apache.jasper.JasperException: 无法为JSP编译类 类型 异常报告消息 无法为JSP编译类:描述 服务器遇到一个意外的情况&#xff0c;阻止它完成请求。例外情况org.apache.jasper.Jas…