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

简介:

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

线程类型:

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.mfbz.cn/a/372748.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unet 实战分割项目、多尺度训练、多类别分割

1. 介绍 之前写了篇二值图像分割的项目&#xff0c;支持多尺度训练&#xff0c;网络采用backbone为vgg的unet网络。缺点就是没法实现多类别的分割&#xff0c;具体可以参考&#xff1a;二值图像分割统一项目 本章只对增加的代码进行介绍&#xff0c;其余的参考上述链接博文 本…

追觅发布多款旗舰新品,双机械臂扫地机器人X40领衔登场

2月2日&#xff0c;追觅科技全球首创仿生“双”机械臂新品发布会在苏州举行。会上&#xff0c;追觅科技中国区总裁郭人杰分享了追觅科技全球化发展的业绩成果。郭人杰称&#xff0c;2019-2023年&#xff0c;追觅科技5年复合年增长率超过100%&#xff0c;增速领跑智能清洁行业&a…

JAVA中的代码块

一、基本语法 [修饰符]{代码; }; {System.out.println(111); } 1.修饰符可选&#xff0c;要写的话也只能写static2.代码块分为两类 使用static修饰的是静态代码块 没有static修饰的叫普通代码块3.逻辑语句可以为任何逻辑语句4.;可以不写 1)静态代码块 作用是对类进行初始化…

SpringBoot源码解读与原理分析(十八)启动SpringApplication逻辑分析

文章目录 6.2 启动SpringApplication6.2.1 前置准备6.2.1.1 计时器对象的使用6.2.1.2 awt的设置6.2.1.3 对比SpringBoot 2.0.x-2.2.x6.2.1.4 对比SpringBoot 2.4.x 6.2.2 获取SpringApplicationRunListeners6.2.2.1 EventPublishingRunListener6.2.2.2 与其他版本的对比 6.2.3 …

TP框架 之think-auth权限认证

一、安装think-auth composer require 5ini99/think-auth二、数据表 -- ---------------------------- -- think_auth_rule&#xff0c;规则表&#xff0c; -- id:主键&#xff0c;name&#xff1a;规则唯一标识, title&#xff1a;规则中文名称 status 状态&#xff1a;为1正常…

我在代码随想录|写代码Day26 |回溯算法|332. 重新安排行程 , 51. N皇后 , 37. 解数独

学习目标&#xff1a; 博主介绍: 27dCnc 专题 : 数据结构帮助小白快速入门 &#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d; ☆*: .&#xff61;. o(≧▽≦)…

私域市场如何突破?解锁高效转化的三个核心要素!

一、私域电商三要素 一是私域、二是社交、三是电商。 私域就是承载用户的地方&#xff0c;比如微信&#xff0c;然后做好私域运营。 社交就是通过内容触达用户于用户建立社交关系。 电商就是通过私域卖产品给用户。 私域电商有几个公式&#xff1a; 社交红利信息关系链互…

redis(6)

文章目录 一、redis clusterRedis Cluster 工作原理Redis cluster 基本架构Redis cluster主从架构Redis Cluster 部署架构说明部署方式介绍 原生命令手动部署原生命令实战案例&#xff1a;利用原生命令手动部署redis cluster 实战案例&#xff1a;基于Redis 5 的redis cluster部…

Nicn的刷题日常之获得月份天数

目录 1.题目描述 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 2.解题 1.题目描述 描述 KiKi想获得某年某月有多少天&#xff0c;请帮他编程实现。输入年份和月份&#xff0c;计算这一年这个月有多少天。 输入描述&#xff1a; 多组输入&#xff0c;一行有两…

外包干了10个月,技术退步明显...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

如何把大容量10G的文件分享给别人?整理了3个简单的方法~

如果文件过大&#xff0c;比如10G的文件发送起来简直问题重重&#xff0c;不仅费时费流量而且还很可能在发送的中途失败&#xff0c;这时候就需要借助一些压缩软件对文件进行压缩&#xff0c;下面就向大家介绍3个好用的压缩软件~ 方法一&#xff1a;使用嗨格式压缩大师压缩后发…

深入理解Java中的二叉树

目录 一、什么是二叉树? 二、二叉树的主要类型 三、二叉树的实现 四、二叉树的应用 五、关于二叉树的题目 引言: 二叉树是计算机科学中常用的一种数据结构&#xff0c;它是由节点组成的层级结构&#xff0c;每个节点最多有两个子节点。在Java编程语言中&#xff0c;二…

架构学习(三):scrapy-redis源码分析并实现自定义初始请求

scrapy-redis源码分析并实现自定义初始请求 前言关卡&#xff1a;如何自定义初始请求背景思考简单又粗暴的方式源码分析 结束 前言 通过这篇文章架构学习(二)&#xff1a;原生scrapy如何接入scrapy-redis&#xff0c;初步入局分布式&#xff0c;我们正式开启scrapy-redis分布式…

C语言递归与迭代并举:双重视角下的C语言阶乘计算实现

引言 计算一个正整数的阶乘是常见的数学问题。阶乘的定义为&#xff1a;n的阶乘&#xff08;记作n!&#xff09;是所有小于及等于n的正整数的乘积。例如&#xff0c;5的阶乘&#xff08;5!&#xff09;就是54321120。下面我们将通过一个使用递归方法实现阶乘的C语言代码示例&am…

Qt|实现时间选择小功能

在软件开发过程中&#xff0c;QtDesigner系统给出的控件很多时候都无法满足炫酷的效果&#xff0c;前一段时间需要用Qt实现选择时间的小功能&#xff0c;今天为大家分享一下&#xff01; 首先看一下时间效果吧&#xff01; 如果有需要继续往下看下去哟~ 功能 1&#xff1a;开…

linux 05重定向和管道管理

01.重定向 例子&#xff1a; 关键字 > date 中的数据要写入 887.txt 02.FD 进程的句柄文件 进程的信息的传输&#xff1a; porcess 会有 0 号文件来接收键盘的信息 1 号文件 向终端 来输出信息 FD文件存储在proc文件中&#xff0c;可以看看 举个例子&#xff1a; 查看pro…

计算机网络原理基础

目录 前言&#xff1a; 1.网络发展史 2.网络通信基础 2.1IP地址 2.1.1定义 2.1.2格式 2.2端口号 2.2.1定义 2.2.2格式 2.3协议 2.3.1定义 2.3.2作用 2.3.3分层 2.4五元组 2.4.1定义 2.4.2组成 3.TCP/IP五层网络模型 3.1模型概念 3.2模型构成 3.3网络分层对应…

docker-compose部署laravel项目实战(主机nginx连接项目容器)(详细配置过程)

我用的是主机上的nginx,没有用docker安装nginx&#xff0c; 所以需要先在主机上安装nginx # 更新系统yum sudo yum update# 安装安装包sudo yum install epel-release sudo yum install wget# 安装Nginx sudo yum install nginx #启动 sudo systemctl start nginx #开机自启动…

C语言笔试题之反转链表(头插法)

实例要求&#xff1a; 1、给定单链表的头节点 head &#xff1b;2、请反转链表&#xff1b;3、最后返回反转后的链表&#xff1b; 案例展示&#xff1a; 实例分析&#xff1a; 1、入参合理性检查&#xff0c;即head ! NULL || head->next ! NULL&#xff1b;2、while循环…

Vue3中使用element-plus菜单折叠后文字不消失

今天使用element-plus中国的导航菜单时&#xff0c;发现菜单栏折叠起来时文字不会自动消失&#xff0c;因为element-plus中内置了菜单折叠文字自动消失的&#xff0c;使用collapsetrue/false即可&#xff0c;但在实际使用中出现了一下问题&#xff1a; 折叠以后文字并没有消失&…
最新文章