Qt中线程的使用

目录

1 .QThread重要信号和函数

1.1 常用共用成员函数

1.2信号和槽函数

1.3静态函数

1.4 任务处理函数

2.关于QThread的依附问题:

3.关于connect连接

4.QThread的使用

5.线程池QThreadPool

5.1. 线程池的原理

5.2.QRunable类

5.3. QThreadPool

6 QtConcurrent

7.QTimer

多线程中使用

8.QElapsedTimer


1 .QThread重要信号和函数

By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread.

1.1 常用共用成员函数

1.2信号和槽函数

1.3静态函数

1.4 任务处理函数

2.关于QThread的依附问题:

QThread是用来管理现成的,他所依附的线程和他所管理的线程不是一个东西。

QThread所依附的线程指的是创建他的线程,即执行QThread t(0)的线程,即主线程。

QThread所管理的线程是run启动的线程;

因此一般情况下,QThread或继承的MyThread中的普通函数或槽函数(非run)都是依赖对象t从而在主线程中执行;而run则不一样;

MoveToThread

3.关于connect连接

自动连接(AutoConnection),默认的连接方式

如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;

如果发送者与接受者处在不同线程,等同于队列连接。

直接连接(DirectConnection)

当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行。

队列连接(QueuedConnection)

当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行。

阻塞连接(QBlockingQueuedConnection)

Same as Qt::QueuedConnection, except that the signalling thread blocks until the slot returns.

4.QThread的使用

用法1:将工作对象和线程对象分离,通过信号和槽函数进行通信触发。

class AsyncObject : public QObject
{Q_OBJECT
public:AsyncObject() = default;~AsyncObject() = default;public slots:void slHandleNotify(int, const QString&);
};void UploadManager::StartServer()
{if (!m_bStarted){m_asyncObject = new AsyncObject();m_pTimerThread = new QThread();m_asyncObject->moveToThread(m_pTimerThread);//所有权交付线程connect(this, &UploadManager::sgNotifyReceived, m_asyncObject, &AsyncObject::slHandleNotify);//默认 AutoConnection this与m_asyncObject不同线程QueuedConnection,//在子线程中运行槽函数 且主线程不等待  Qt::BlockingQueuedConnection则同步等待m_pTimerThread->start();m_bStarted = true;}
}

用法2:继承QThread,重写run函数。

        这种在程序中添加子线程的方式是非常简单的,但是也有弊端,假设要在一个子线程中处理多个任务所有的处理逻辑都需要写到run()函数中,这样该函数中的处理逻辑就会变得非常混乱,不太容易维护。

         

class SearchRecordThread:QThread
{QOBJECTpublic:SearchRecordThread(Qbject*parent = nullptr);protected:void run() override;
}SearchRecordThread::SearchRecordThread(Qbject*parent):QThread(parent)
{}void SearchRecordThread::run()
{//子线程中耗时的数据库搜索业务
}void testThread::test()
{SearchRecordThread* searchRecordThread= new SearchRecordThread;searchRecordThread->start();
}

5.线程池QThreadPool

5.1. 线程池的原理

        如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,如果频繁创建线程和销毁线程需要时间,大大降低系统的效率

        线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件), 则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

5.2.QRunable类

The QRunnable class is the base class for all runnable objects. 即QThread也是继承QRunable,因此用法一致重写run函数即可。

在 Qt 中使用线程池需要先创建任务,添加到线程池中的每一个任务都需要是一个 QRunnable 类型,因此在程序中需要创建子类继承 QRunnable 这个类,然后重写 run() 方法,在这个函数中编写要在线程池中执行的任务,并将这个子类对象传递给线程池,这样任务就可以被线程池中的某个工作的线程处理掉了

//继承QRunnable 任务重写在run()里面
class QueryRemoteControlRunnable : public QRunnable
{
public:QueryRemoteControlRunnable() = default;QueryRemoteParam qrp;void run();
};//主线程中将该对象扔到线程池,会分配空闲的线程
void RequstRunables::queryRemoteControl(const QueryRemoteParam& qrp)
{QueryRemoteControlRunnable* pRun = new(std::nothrow)QueryRemoteControlRunnable();if (!pRun){cLogger("Runnable")->error() << __FUNCTION__ << "从堆中创建QueryRemoteControlRunnable失败";return;}pRun->qrp = qrp;QThreadPool::globalInstance()->start(pRun);
}

5.3. QThreadPool

Qt 中的 QThreadPool 类管理了一组 QThreads, 里边还维护了一个任务队列。QThreadPool 管理和回收各个 QThread 对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局 QThreadPool 对象,可以通过调用 globalInstance() 来访问它。也可以单独创建一个 QThreadPool 对象使用。

一般情况下,我们不需要在 Qt 程序中创建线程池对象,直接使用 Qt 为每个应用程序提供的线程池全局对象即可。得到线程池对象之后,调用 start() 方法就可以将一个任务添加到线程池中,这个任务就可以被线程池内部的线程池处理掉了,使用线程池比自己创建线程的这种多种多线程方式更加简单和易于维护 .

void MyThreadPool::InitMyThreadPool()
{if (!m_MyThreadPool){QMutexLocker Lock(&m_MyPoolMutex);if (!m_MyThreadPool){m_MyThreadPool = new QThreadPool;//创建线程池if (m_MyThreadPool){m_MyThreadPool->setMaxThreadCount(4);}}}
}QThreadPool *MyThreadPool::GetMyThreadPool()
{if (!m_MyThreadPool){InitMyThreadPool();}return m_MyThreadPool;
}void MyThreadPool::DestoryThreadPool()
{if (m_MyThreadPool){m_MyThreadPool->waitForDone();}
}

6 QtConcurrent

QtConcurrent命名空间中定义了高级线程API,避免使用低级原生线程,更加简化。

使用:包含Concurrent模块

QFuture<T> QtConcurrent::run(Function function, ...)
Equivalent toQtConcurrent::run(QThreadPool::globalInstance(), function, ...);/*
Runs function in a separate thread. The thread is taken from the global QThreadPool. Note that function may not run immediately; function will only be run once a thread becomes available.
T is the same type as the return value of function. Non-void return values can be accessed via the QFuture::result() function.
Note that the QFuture returned by QtConcurrent::run() does not support canceling, pausing, or progress reporting. The QFuture returned can only be used to query for the running/finished status and the return value of the function.
See also Concurrent Run.
*/QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
/*  
Runs function in a separate thread. The thread is taken from the QThreadPool pool. Note that function may not run immediately; function will only be run once a thread becomes available.
T is the same type as the return value of function. Non-void return values can be accessed via the QFuture::result() function.
Note that the QFuture returned by QtConcurrent::run() does not support canceling, pausing, or progress reporting. The QFuture returned can only be used to query for the running/finished status and the return value of the function.
*/QtConcurrent::run(m_notifyThreadPool, [=]() {/*working*/
});QPixmap QPixmapLoader::loadRemotePixmap(const QString &strUniqueId, int picType,const QString& strClientHash,const QString& strPicPath)
{auto &&pixmap = loadBufferedRemotePixmap(strUniqueId, picType);if (pixmap.isNull() && !strUniqueId.isEmpty()) {QtConcurrent::run(&m_threadPool, std::bind(&QPixmapLoader::loadPixmapFromRemote, this, strUniqueId, picType, strClientHash, strPicPath));}return pixmap;
}#include<QThread>
#include<QtConcurrent>
void Test{QtConcurrent::run([]{std::cout  << QThread::currentThread() << std::endl;});QtConcurrent::run([]{std::cout << QThread::currentThread() << std::endl;});QThread::msleep(100);QByteArray str = "Hello,World,Welcome,to,WestWorld";QFuture<QList<QByteArray>>future =  QtConcurrent::run(str, &QByteArray::split, ',');QList<QByteArray> result = future.result();for (auto iter : result){qDebug() << iter;}
}

7.QTimer

多线程中使用

        In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.

//.h
class MyTimerThread : public QThread
{Q_OBJECTpublic:MyTimerThread(QObject *parent=nullptr);~MyTimerThread();void addTimer(QTimer* timer);protected:virtual void run();
private:QVector<QTimer*> m_timerList;
};//cpp
class MyTimerThread : public QThread
{Q_OBJECTpublic:MyTimerThread(QObject *parent=nullptr);~MyTimerThread();void addTimer(QTimer* timer);protected:virtual void run();
private:QVector<QTimer*> m_timerList;
};
MyTimerThread::MyTimerThread(QObject *parent)
{
}MyTimerThread::~MyTimerThread()
{quit();wait();
}void MyTimerThread::addTimer(QTimer* timer)
{if (nullptr == timer){return;}//timer所属权都交给子线程timer->moveToThread(this);m_timerList.append(timer);
}void MyTimerThread::run()
{for (auto pTimer : m_timerList) {pTimer->start();}exec();//子线程里面使用QTimer需要事件循环for (auto pTimer : m_timerList) {pTimer->stop();delete pTimer;}
}//使用测试
int Server::startServer()
{m_pTimerThread = new MyTimerThread();m_timerHeartBeat = new QTimer();m_timerHeartBeat->setInterval(3000);m_pTimerThread->addTimer(m_timerHeartBeat);//子线程中启动 Qt::DirectConnection 子线程中心跳connect(m_timerHeartBeat, &QTimer::timeout, this, &Server::HeartBeat, Qt::DirectConnection);//...
}
class DevManager : public QObject
{Q_OBJECTpublic:bool startServer();//...public slots:void uploadParkSlotToDev();
private:DevManager(QObject *parent);QTimer m_timerParksLot;QThread *m_ParksLotThread = nullptr;
};bool DevManager::startServer()
{if (!m_bStarted){int IntervalTime = 3000;m_timerParksLot.setInterval(IntervalTime);m_ParksLotThread = new QThread(this);m_timerParksLot.moveToThread(m_ParksLotThread);//m_timerParksLot所有权交给m_ParksLotThreadconnect(m_ParksLotThread, &QThread::started, &m_timerParksLot, static_cast<void (QTimer::*)()> (&QTimer::start));//主线程statred触发connect(&m_timerParksLot, &QTimer::timeout, this, &DevManager::uploadParkSlotToETC, Qt::DirectConnection);//子线程对象发送的信号 DirectConnection连接 发送者线程(子)执行m_ParksLotThread->start();m_bStarted = true;}return m_bStarted;
}

8.QElapsedTimer

单调时钟,主要记录两个事件之间的时长(准),无法转换为人类可以读取的形式,QTimer非单调时钟,精度与操作系统有关。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/40175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装维修制氮设备的注意指南

制氮设备在许多工业领域都发挥着重要作用&#xff0c;无论是确保生产过程中的氮气供应&#xff0c;还是维持设备的稳定运行&#xff0c;正确的安装和维修都是关键。以下是一些重要的注意事项&#xff0c;帮助您顺利完成制氮设备的安装与维修工作。 一、安装注意事项 (一)选址与…

VUE自定义新增、复制、删除dom元素

功能需求&#xff0c;能灵活新增或删除一个dom元素&#xff0c;在此dom元素中还存在能灵活新增、删除的dom元素。实现后功能图如下&#xff1a; 点击新增策略&#xff0c;能新增整个策略dom 实现思路&#xff1a;定义一个数量和一个数组&#xff0c;然后使用循环遍历展示内容&a…

将iStoreOS部署到VMware ESXi变成路由器

正文共&#xff1a;888 字 19 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面把iStoreOS部署到了VMware workstation上&#xff08;将iStoreOS部署到VMware Workstation&#xff09;。如果想把iStoreOS直接部署到ESXi上&#xff0c;你会发现转换镜像不能直接生成OVF或者OV…

css+js实现导航栏色块跟随滑动+点击后增加样式

这篇文章&#xff0c;我给大家分享一个导航菜单的效果。用cssJS实现&#xff0c;效果如图&#xff1a; 本例实现效果&#xff1a;当鼠标移动到其他菜单项时&#xff0c;会有个背景色块跟随鼠标横向平滑移动。当鼠标点击后&#xff0c;被点击的菜单名称文字字体会加粗。 现在&…

《数字图像处理与机器视觉》案例四 基于分水岭算法的粘连物体的分割与计数

一、引言 分水岭算法&#xff08;Watershed Algorithm&#xff09;&#xff0c;是一种基于拓扑理论的数学形态学的分割方法&#xff0c;其基本思想是把图像看作是测地学上的拓扑地貌&#xff0c;图像中每一点像素的灰度值表示该点的海拔高度&#xff0c;每一个局部极小值及其影…

SpringBoot 集成Swagger在线接口文档 接口注解

介绍 Swagger接口文档是一种自动生成、描述、调用和可视化的RESTful风格Web服务接口文档的工具。它通过一系列的规范和自动化工具&#xff0c;极大地简化了后端开发人员与前端开发人员之间的协作。 依赖 <!--swagger--> <dependency><groupId>io.springfo…

「媒体邀约」天津媒体资源?媒体邀约宣传报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 天津拥有丰富的媒体资源&#xff0c;利用这些资源进行有效…

ICMP协议详解及尝试用ping和tracert捕抓ICMP报文

一、ICMP协议 1.1、定义 ICMP&#xff08;Internet Control Message Protocol&#xff0c;互联网控制消息协议&#xff09;是一个支持IP层数据完整性的协议&#xff0c;主要用于在IP主机、路由器之间传递控制消息。这些控制消息用于报告IP数据报在传输过程中的错误&#xff0c…

C++ 语法

一、头文件与源文件 头文件用于声明函数,类似于java中service层的接口; 源文件用于实现头文件函数,相当于java中serviceImpl层的实现类; 定义接口 实现接口 使用接口 二、指针概述 定义与使用 定义一个指针p用于存a变量的内存地址,即指针就是地址; 解引用可以获取或修改…

40岁以上的中年人很难找到工作

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 你们有没有发现&#xff0c;90%的40岁以上的中年人&#xff0c;为了多挣钱&#xff0c;几乎除了吃饭和睡觉之外&#xff0c;都在拼命加班劳作&#xff0c;只要一停下来&#xff0c;心里就有一种内疚感&#xff0c;…

【Elasticsearch】Elasticsearch动态映射与静态映射详解

文章目录 &#x1f4d1;前言一、Elasticsearch 映射概述1.1 什么是映射&#xff1f;1.2 映射的分类 二、动态映射2.1 动态映射的定义2.2 动态映射的优点2.3 动态映射的缺点2.4 动态映射的应用场景2.5 动态映射的配置示例 三、静态映射3.1 静态映射的定义3.2 静态映射的优点3.3 …

机器学习简介--NLP(二)

机器学习简介 机器学习简介机器学习例子机器学习分类有监督学习有监督学习的应用 无监督学习 机器学习常见概念数据集k折交叉验证过拟合欠拟合评价指标 机器学习简介 机器学习例子 问题&#xff1a; 2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;&#xff1f;&#…

【CV炼丹师勇闯力扣训练营 Day22:§7 回溯1】

CV炼丹师勇闯力扣训练营 代码随想录算法训练营第22天 回溯法其实就是暴力查找,回溯的本质是穷举&#xff0c;穷举所有可能&#xff0c;然后选出我们想要的答案&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割…

Ubuntu18.04新安装--无网络连接、重启黑屏解决教程

一、安装Ubuntu Ubuntu安装需要U盘作为启动盘&#xff0c;在目前教新的电脑中选中GPT作为分区&#xff0c;制作启动盘&#xff0c;其中在安装双系统Ubuntu时&#xff0c;以自定义格式作为存储空间。详细安装过程以以及如何分区请参考下列链接&#xff1a;内含详细安装过程&…

VS Code 常用快捷键大全

Visual Studio Code 是目前最好用的代码编辑器之一。它提供了许多开箱即用的功能以及丰富的第三方扩展&#xff0c;本文将分享常用的 VS Code 快捷键&#xff0c;助你提高开发效率&#xff01; 代码导航 跳转指定行&#xff1a;快速跳转到文件中的指定行&#xff0c;只需按下快…

Unity 数据持久化【PlayerPrefs】

1、数据持久化 文章目录 1、数据持久化PlayerPrefs基本方法1、PlayerPrefs概念2、存储相关3、读取相关4、删除数据思考 信息的存储和读取 PlayerPrefs存储位置1、PlayerPrefs存储的数据在哪个位置2、PlayerPrefs 数据唯一性思考 排行榜功能 2、Playerprefs实践1、必备知识点-反…

解决 Layout Inspector无法查看Component Tree 布局层级信息 | Android Studio Koala

问题描述 Tool -> Layout Inspector 显示下图&#xff0c;无法生成.li文件查看Component Tree&#xff0c;变成实时的Preview并功能点击操作&#xff0c;跟模拟器一样。 原因&#xff1a;默认勾选了"Enable embedded Layout Inspector"&#xff0c;启用了嵌入式…

SpringCloud进阶篇

文章目录 网关快速入门创建模块引入依赖修改启动类配置路由路由过滤(一般不用) 自定义GlobalFilter登录校验登录校验过滤器 微服务获取用户信息保存用户信息到请求头拦截器获取用户信息 OpenFeign传递用户信息配置共享添加共享配置拉取共享配置 配置热更新添加配置到Nacos配置热…

数据结构初阶 堆的问题详解(三)

题目一 4.一棵完全二叉树的节点数位为531个&#xff0c;那么这棵树的高度为&#xff08; &#xff09; A 11 B 10 C 8 D 12 我们有最大的节点如下 假设最大高度为10 那么它的最多节点应该是有1023 假设最大高度为9 那么它的最多节点应该是 511 所以说这一题选B 题目二 …

指挥中心操作台的形状及空间布局

在现代化的指挥中心&#xff0c;操作台的形状设计至关重要&#xff0c;它不仅影响着操作人员的工作效率和舒适度&#xff0c;还关系到整个指挥系统的运行效果。常见的指挥中心操作台形状多种多样&#xff0c;以满足不同的功能需求和空间布局。 直线型操作台 直线型操作台是最为…