浅谈QT的几种线程的使用和区别。

news2024/11/25 12:34:43

简介:

线程是操作系统中的基本执行单元,是一个独立的执行路径。每个线程都有自己的栈空间,用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行,从而实现并发处理,提高程序的性能和响应能力。
与进程不同的是,线程是轻量级的,它们共享同一进程的地址空间,这意味着它们可以访问相同的内存和文件资源,从而更容易地共享数据和通信

线程类型:

1、QThread。
2、QObject+moveToThread实现。
3、QThreadPool+QRunnable实现。
4、QFuture+QtConcurrent实现。
5、std::thread实现,不是QT自身的,但是在Qt中使用比较方便也介绍下。

QThread:

介绍:优点是简单易用,能轻松地创建和管理线程。它提供了一些方法来控制线程的生命周期,包括start()和quit()方法来启动和停止线程,以及wait()方法来等待线程完成。
QThread还提供了一些信号来管理线程。例如,finished()信号在线程完成执行后发出,error()信号在线程发生错误时发出。它的线程入口是从run函数开始。
但是它也存在缺点,它只有run函数内部才是在线程范围内,其它函数都是在主线程中。
适用场景:生命周期长但是交互少的场景。
代码:
.h

#include <QThread>
class MThread : public QThread
{
    Q_OBJECT
public:
    MThread();

    void run();
public slots:
    void test(int val);
};

.cpp

#include "mthread.h"
#include <QDebug>

MThread::MThread()
{
    qDebug()<<"main thread"<<QThread::currentThreadId();
}

void MThread::test(int val)
{
    qDebug()<<"test val"<<QThread::currentThreadId()<<val;
}

void MThread::run()
{
    qDebug()<<"thread 1"<<QThread::currentThreadId();
}

调用

    MThread *thread = new MThread();
    connect(this,&Widget::sigSendVal,thread,&MThread::test);
    thread->start();
    this->sigSendVal(66);
    thread->wait();
    thread->exit();

结果:
在这里插入图片描述

QObject+moveToThread实现:

介绍:优点是交互灵活,且跟主线程之间的所有信号槽都是在线程中执行,QThread拥有的线程控制它都具有,如start,quit,wait等等。
缺点:代码逻辑较复杂,使用灵活性没有那么高,由于创建的类较多,内存占用较高,性能相对较低。
适用场景:生命周期长,交互频繁且需要交互逻辑也在线程中的场景。
代码:
.h

#include <QObject>
class MThreadObject : public QObject
{
    Q_OBJECT
public:
    MThreadObject();
public slots:
    void startThread();
    void slotTest(int val);
};

};

.cpp

#include "mthreadobject.h"
#include <QThread>
#include <QDebug>

MThreadObject::MThreadObject()
{
    qDebug()<<"main thread"<<QThread::currentThreadId();
}

void MThreadObject::startThread()
{
    qDebug()<<"thread 2"<<QThread::currentThreadId();
}

void MThreadObject::slotTest(int val)
{
    qDebug()<<"test val"<<QThread::currentThreadId()<<val;
}

调用

    MThreadObject* object = new MThreadObject();
    QThread* thread2 = new QThread;
    object->moveToThread(thread2);
    connect(thread2,&QThread::started,object,&MThreadObject::startThread);
    connect(this,&Widget::sigSendVal,object,&MThreadObject::slotTest);
    thread2->start();
    emit sigSendVal(66); //this->sigSendVal(66) 两种方法都可以

结果
在这里插入图片描述

QThreadPool+QRunnable实现:

介绍:由于线程池原理就是将一堆任务分到设置的几个线程中,按照优先级先后执行,所有在存在大批量任务的时候,可以有效的管理线程的开销。QThreadPool c++实现
缺点:使用起来不是很灵活,由于存在任务排队和优先级设置,所有管理较复杂。
适用场景:需要创建大量生命周期短小,且逻辑重复简单的任务。

int activeThreadCount() const //当前的活动线程数量
void clear()//清除所有当前排队但未开始运行的任务
int expiryTimeout() const//线程长时间未使用将会自动退出节约资源,此函数返回等待时间
int maxThreadCount() const//线程池可维护的最大线程数量
void releaseThread()//释放被保留的线程
void reserveThread()//保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
void setExpiryTimeout(int expiryTimeout)//设置线程回收的等待时间
void setMaxThreadCount(int maxThreadCount)//设置最大线程数量
void setStackSize(uint stackSize)//此属性包含线程池工作线程的堆栈大小。
uint stackSize() const//堆大小
void start(QRunnable *runnable, int priority = 0)//加入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable ,后续介绍
bool tryStart(QRunnable *runnable)//尝试启动一个
bool tryTake(QRunnable *runnable)//删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
bool waitForDone(int msecs = -1)//等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出
void setAutoDelete(bool flag = true)//QRunnable的设置项,用来标识是否在运行结束后自动由线程池释放空间

代码
.h

#include <QObject>
#include <QRunnable>
class MRunnable : public QObject,public QRunnable
{
    Q_OBJECT
public:
    MRunnable(int num);
    void run();
    void setval(int index);
    int _index = 0;
    int _num = 0;
};

.cpp

#include "mrunnable.h"
#include <QDebug>
#include <QThread>

MRunnable::MRunnable(int num)
{
    qDebug()<<"main thread"<<QThread::currentThreadId();
}

void MRunnable::setval(int index)
{
    qDebug()<<"---------setval"<<index<<QThread::currentThreadId();
    _index = index;
}

void MRunnable::run()
{
    qDebug()<<_index<<_num<<"thread 3"<<QThread::currentThreadId();
    QThread::msleep(200);
}

调用

    QThreadPool pool;
    pool.setMaxThreadCount(3);
    QList<MRunnable*> runs;
    for (int i = 0; i < 5; ++i) {
        MRunnable *run = new MRunnable(44);
        run->setval(i);
        pool.start(run);
    }
    for (int i = 0; i < runs.size(); ++i) {
        delete runs[i];
    }
    runs.clear();

结果:
在这里插入图片描述

QFuture+QtConcurrent实现:

介绍:QFuture + Qt Concurrent是Qt提供的一个并发编程框架,用于简化多线程和并行计算的开发。它提供了一组易于使用的函数和类,可以方便地在多线程环境下处理并发任务。优点简单易用、自动将大的问题拆分成更小的任务,并分配给不同的线程并行执行、异步计算,不会阻塞主线程。(详细介绍1、详细介绍2)
缺点:交互麻烦。
使用场景:需要临时使用一下线程的场景。
代码
.pro
Qt += concurrent
.h

#include <QWidget>
#include <QDebug>
#include <QFuture>
#include <QtConcurrent>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void slotFinish();
private:
    Ui::Widget *ui;
    QFuture<int> m_future;
    QFutureWatcher<int> m_watcher;
};

.cpp

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    auto func([&](int val){
        val = 2*val;
        qDebug()<<"thread 4"<<val<<QThread::currentThreadId();
        return val;
    });

	//异步调用
    QObject::connect(&m_watcher, &QFutureWatcher<void>::finished, this, &Widget::slotFinish);
    int val = 123;
    m_future = QtConcurrent::run(func,val);
    m_watcher.setFuture(m_future);

//    future.waitForFinished();//同步调用
    qDebug()<<"main thread"<<QThread::currentThreadId()<<m_future.result();
}

Widget::~Widget()
{
    delete ui;
}



void Widget::slotFinish()
{
    int res = m_future.result();
    qDebug()<<"watcher finish"<<res<<QThread::currentThreadId();
}

结果:
在这里插入图片描述

std::thread实现:

介绍:直接调用,优点使用方便灵活。缺点:无法完成复杂的交互。
适用场景:适用需要临时创建线程的场景下。
代码

#include <thread>
void test()
{
    std::thread thread5([&](){
       qDebug()<<"thread 5"<<QThread::currentThreadId();
    });
    thread5.detach();
    qDebug()<<"main thread"<<QThread::currentThreadId();```
}

结果
在这里插入图片描述

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

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

相关文章

【Docker】入门到精通(常用命令解读)

一、准备工作 1.配置Docker的yum库 首先要安装一个yum工具 yum install -y yum-utils安装成功后&#xff0c;执行命令&#xff0c;配置Docker的yum源&#xff1a; yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo2.安装Docker 执…

Go语言深度解析:探索 crypto/md5 标准库的强大功能

Go语言深度解析&#xff1a;探索 crypto/md5 标准库的强大功能 引言Go语言和MD5的基础知识MD5算法简介Go语言概述Go中的MD5实现 crypto/md5 库的使用方法基本用法处理大型数据安全注意事项 实际案例分析示例1&#xff1a;文件的MD5校验示例2&#xff1a;网络数据的MD5哈希示例3…

第9章 安全漏洞、威胁和对策(9.11-9.16)

9.11 专用设备 专用设备王国疆域辽阔&#xff0c;而且仍在不断扩张。 专用设备是指为某一特定目的而设计&#xff0c;供某一特定类型机构使用或执行某一特定功能的任何设备。 它们可被看作DCS、物联网、智能设备、端点设备或边缘计算系统的一个类型。 医疗设备、智能汽车、…

154基于matlab的二维元胞自动机模拟森林火灾(生命游戏 )和模拟收费站交通流

基于matlab的二维元胞自动机模拟森林火灾&#xff08;生命游戏 &#xff09;和模拟收费站交通流。全国大学生美国建模竞赛&#xff0c;程序已调通&#xff0c;可直接运行。 154 元细胞自动机 森林起火 收费站交通 (xiaohongshu.com)

大人不华,君子务实|复旦大学-华盛顿大学EMBA C18班优秀学生代表周靖毕业典礼演讲

周靖      Ecarx集团首席财务官      亲爱的Mazzeo院长、殷院长、尊敬的各位老师们、家人们以及各位同学们和毕业生们&#xff1a;      今天&#xff0c;当我们站在开启人生新篇章的分岔路&#xff0c;真是五味杂陈&#xff0c;感慨万千。对我们而言&#xff0c;能…

Day 35 | 贪心 860.柠檬水找零 、 406.根据身高重建队列 、 452. 用最少数量的箭引爆气球

860.柠檬水找零 题目 文章讲解 视频讲解 思路&#xff1a;分别列出三种支付方式对应的找零情况 class Solution {public boolean lemonadeChange(int[] bills) {int five 0, ten 0, twenty 0;for (int i 0; i < bills.length; i) {if (bills[i] 5) {five;} else if…

undefined symbol: avio_protocol_get_class, version LIBAVFORMAT_58

rv1126上进行编译和在虚拟机里面进行交叉编译ffmpeg都不行 解决办法查看 查看安装的ffmpeg链接的文件 ldd ./ffmpeg rootEASY-EAI-NANO:/home/nano/ffmpeg-4.3.6# ldd ffmpeg linux-vdso.so.1 (0xaeebd000)libavdevice.so.58 > /lib/arm-linux-gnueabihf/libavde…

防火墙是什么?聊聊如何轻松缓解应用漏洞

数字经济时代&#xff0c;也是应用爆炸的时代。企业越来越多地使用分布式应用架构构建现代微服务&#xff0c;以适应日益增长的应用使用量并提供更高的性能。与此同时却出现许多热点**&#xff0c;如供应链安全、零日漏洞、数据泄露等。忽视安全防护的企业会面临丢失业务的风险…

npm install express -g报错或一直卡着,亲测可解决

问题描述&#xff1a; 最近学习vue3前端框架&#xff0c;安装Node.js之后&#xff0c;在测试是否可行时&#xff0c;cmd窗口执行了&#xff1a;npm install express -g&#xff0c;发现如下图所示一直卡着不动&#xff0c;最后还报错了&#xff0c;网上找了好久&#xff0c;各…

操作系统基础:文件系统基础【下】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 ⚔️1 文件的基本操作⚖️1.1 总览⚖️1.2 几种基本操作&#x1f52d;1.2.1 创建文件&#x1f52d;1.2.2 删除文件&#x1f52d;1.2.3 打开文件&#x1f52d;1.2.4 关闭文件…

python算法与数据结构---动态规划

动态规划 记不住过去的人&#xff0c;注定要重蹈覆辙。 定义 对于一个模型为n的问题&#xff0c;将其分解为k个规模较小的子问题&#xff08;阶段&#xff09;&#xff0c;按顺序求解子问题&#xff0c;前一子问题的解&#xff0c;为后一子问题提供有用的信息。在求解任一子…

Multisim14.0仿真(四十一)交通信号灯仿真设计

一、功能简介&#xff1a; 1&#xff09;、采用两片74LS192做减法计数器&#xff0c;实现倒计时功能。 2&#xff09;、采用DCD数码管显示时间。 3&#xff09;、采用4个TRAFFIC_LIGHT_SINGLE红绿灯 4&#xff09;、采用74LS160和74LS138实现对红绿灯的逻辑控制。 5&#xff09…

Python 潮流周刊#38:Django + Next.js 构建全栈项目

△△请给“Python猫”加星标 &#xff0c;以免错过文章推送 你好&#xff0c;我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容&#xff0c;大部分为英文。本周刊开源&#xff0c;欢迎投稿[1]。另有电报频道[2]作为副刊&#xff0c;补充发布更加丰富的资讯&#xff0c;…

elementUI 表格中如何合并动态数据的单元格

elementUI 表格中如何合并动态数据的单元格 ui中提供的案例是固定写法无法满足 实际开发需求 下面进行改造如下 准备数据如下 //在表格中 设置单元格的方法 :span-method"spanMethodFun" <el-table :data"tableData" border :span-method"spa…

私有化部署一个吃豆人小游戏

目录 效果 安装步骤 1.安装并启动httpd 2.下载代码 3.启动httpd 使用 效果 安装步骤 1.安装并启动httpd yum -y install httpd 2.下载代码 进入目录 cd /var/www/html/ 下载 git clone https://gitee.com/WangZhe168_admin/pacman-canvas.git 3.启动httpd syste…

docker更换镜像源

添加的镜像源 {"registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com", "https://reg-mirror.qiniu.com/", "https://docker.mirrors.ustc.edu.cn"] }docker更换镜像源之后一定要重启守卫 systemctl daemon-reloaddock…

网络原理TCP/IP(5)

文章目录 IP协议IP协议报头地址管理网段划分特殊的IP地址路由选择以太网认识MAC地址对比理解MAC地址和IP地址DNS&#xff08;域名服务器&#xff09; IP协议 IP协议主要完成的工作是两方面&#xff1a; 地址管理&#xff0c;使用一套地址体系&#xff0c;来描述互联网上每个设…

响应式开发如何设置断点,小屏幕界面该如何显示(有动图)

Hi&#xff0c;我是贝格前端工场&#xff0c;本期分享响应式开发&#xff0c;如何设置屏幕断点&#xff0c;pc页面布局到了移动端之后该如何布局的问题&#xff0c;微软也提供了设置屏幕断点的动图演示&#xff0c;非常直观。 一、什么是响应式开发&#xff0c;为何要设置屏幕断…

问题:0xc8前面加(byte) #人工智能#学习方法的原因是因为0xc8大于??????????? 。 #微信#其他#微信

问题&#xff1a;0xc8前面加&#xff08;byte&#xff09;的原因是因为0xc8大于??????????? 。 参考答案如图所示

【Linux】信号-下

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f449;&#x1f3fb;信号递达&#xff0c;信号未决&#x…