Qt线程QThread详解

news/2024/4/26 22:29:05/文章来源:https://blog.csdn.net/zheng19880607/article/details/128104560

目录

      • 前言
      • 1.QThread介绍
      • 2.QThread示例一
      • 3.QThread示例二
      • 4.线程同步

前言

在这里插入图片描述
在程序中使用线程可以提高程序的性能、并发性、响应性和稳定性,使得程序设计更加灵活和简单。但是,线程编程也有一些挑战,如线程安全性和死锁等问题需要格外注意。我们使用QT框架编程时,可以用框架提供的线程类QThread来管理线程。本文将介绍使用QThread编程时的两种方式,并给出一个数据同步的示例。

1.QThread介绍

在介绍QThread之前先复习下线程的定义,线程是操作系统中的基本执行单元,是一个独立的执行路径。每个线程都有自己的栈空间,用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行,从而实现并发处理,提高程序的性能和响应能力。
与进程不同的是,线程是轻量级的,它们共享同一进程的地址空间,这意味着它们可以访问相同的内存和文件资源,从而更容易地共享数据和通信。
QThread是Qt框架中用于创建和管理线程的类。可以用QThread轻松地创建新的线程并将任务分配给它们还可以创建自己的线程类并从QThread继承,也可以使用QThread的静态函数创建线程。

QThread的主要优点是简单易用,能轻松地创建和管理线程。它提供了一些方法来控制线程的生命周期,包括start()和quit()方法来启动和停止线程,以及wait()方法来等待线程完成。

QThread还提供了一些信号来管理线程。例如,finished()信号在线程完成执行后发出,error()信号在线程发生错误时发出。

2.QThread示例一

在这个示例中有两个自定义线程:IncrementThread和DoubleThread,它们分别用于增加数字和将数字乘以2。这些线程都使用QThread类,并且都包含一个信号,以便在线程运行时向主线程发送结果。

#include <QObject>
#include <QThread>
#include <QVector>class IncrementThread : public QThread {Q_OBJECTpublic:IncrementThread(int count) : count(count) {}signals:void countChanged(int count);protected:void run() {for (int i = 1; i <= count; ++i) {emit countChanged(i);msleep(1000);}}private:int count;
};class DoubleThread : public QThread {Q_OBJECTpublic:DoubleThread(const QVector<int>& nums) : nums(nums) {}signals:void doubled(int num);protected:void run() {for (int num : nums) {emit doubled(num * 2);msleep(1000);}}private:QVector<int> nums;
};

在MainWindow类中,我们将创建线程,并将它们的信号连接到槽函数onCountChanged和onDoubled中。每当IncrementThread发出onCountChanged信号时,onDoubled将在主线程中更新标签的文本,以显示当前进度。类似地,每当DoubleThread发出doubled信号时,onDoubled将在主线程中更新标签的文本,以显示结果。

我们在构造函数中创建这两个线程,将它们的信号连接到槽函数中,并启动线程。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);ui->label->setText("Waiting for results...");incrementThread = new IncrementThread(5);doubleThread = new DoubleThread({1, 2, 3, 4, 5});connect(incrementThread, &IncrementThread::countChanged, this, &MainWindow::onCountChanged);connect(doubleThread, &DoubleThread::doubled, this, &MainWindow::onDoubled);incrementThread->start();doubleThread->start();
}void MainWindow::onCountChanged(int count)
{ui->label->setText(QString("Incrementing %1").arg(count));qDebug()  <<  "Incrementing " << count;
}void MainWindow::onDoubled(int num)
{ui->label->setText(QString("Doubling %1").arg(num));qDebug()  << "Doubling " << num;
}MainWindow::~MainWindow()
{delete ui;
}

下面是程序运行时控制台输出的信息,从中可以看出两个线程是交替运行的。
在这里插入图片描述

3.QThread示例二

在这个示例中,我们创建了一个Worker类,该类包含一个doWork槽函数,用于在新线程中执行任务。在main函数中,我们创建了一个新的QThread对象和一个Worker对象,并将Worker对象的doWork槽函数连接到QThread对象的started信号上。然后,我们将Worker对象通过moveThread()方法移动到新线程中,并启动新线程。在主线程中,我们也有一个类似的循环,用于展示主线程和新线程是同时执行的。在循环结束后,我们调用了quit函数,以停止新线程的事件循环,并使用wait函数等待线程完成。

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <chrono>class Worker : public QObject
{Q_OBJECTpublic:Worker(int num_iterations) : m_num_iterations(num_iterations) {}public slots:void doWork() {for (int i = 0; i < m_num_iterations; i++) {qDebug() << "Thread function is running...";QThread::msleep(1000);}}private:int m_num_iterations;
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int num_iterations = 5;QThread thread;Worker worker(num_iterations);//把线程启动信号与worker的doWork槽函数绑定在一起QObject::connect(&thread, &QThread::started, &worker, &Worker::doWork);//将woker对象移动到thread线程中执行worker.moveToThread(&thread);thread.start();for (int i = 0; i < num_iterations; i++) {qDebug() << "Main thread is running...";QThread::msleep(500);}thread.quit();thread.wait();return a.exec();
}

注意,若调用moveToThread()方法将worker对象移动到某个线程,则worker不能指定parent指针。默认情况下,对象是在哪个线程创建的,就属于哪个线程。

4.线程同步

在这个示例中,我们将创建一个线程并在其中使用QWaitCondition和QMutex来实现线程同步。

#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QDebug>class MyThread : public QThread {
public:void run() override {//加锁QMutexLocker locker(&mutex);qDebug() << "Thread started";// Do some work hereqDebug() << "Thread waiting";//线程挂起,直到调用wakeUp函数后,继续往下执行condition.wait(&mutex);qDebug() << "Thread resumed";// Do more work hereqDebug() << "Thread finished";}void wakeUp() {QMutexLocker locker(&mutex);condition.wakeOne();}private:QWaitCondition condition;QMutex mutex;
};int main(int argc, char *argv[])
{MyThread thread;thread.start();// Do some other work herethread.wakeUp();thread.wait();return 0;
}

在这个示例中,我们创建了一个MyThread类,继承自QThread,重写了run()函数,在其中执行一些工作。在该函数中,我们获取了一个QMutexLocker对象,以确保线程同步,并输出一些信息来显示线程已启动。

然后,我们调用QWaitCondition的wait()方法,将线程挂起,直到其他线程调用了wakeUp()方法。在等待期间,我们释放了QMutexLocker,以允许其他线程对共享资源进行访问。

在wakeUp()方法中,我们获取了QMutexLocker对象,以确保线程同步,并调用QWaitCondition的wakeOne()方法,以唤醒一个挂起的线程。

在主线程中,我们创建了一个MyThread对象并调用start()方法来启动线程。然后,我们执行一些其他工作,并在最后调用wakeUp()方法来唤醒线程。最后,我们调用wait()方法等待线程完成。

这个示例演示了如何使用QWaitCondition和QMutex来实现线程同步。QWaitCondition用于等待线程唤醒,而QMutex用于保护共享资源并防止竞争条件。通过使用这些类,我们可以编写线程安全的代码,并避免死锁和竞争条件的问题。

以上就是本文的全部内容了,希望对大家有帮助,如有问题,欢迎指正!

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

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

相关文章

【1】linux命令每日分享——mkdir

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…

【机器学习】决策树-ID3算法

1.ID3算法 ID3算法利用信息增益进行特征的选择进行树的构建。信息熵的取值范围为0~1&#xff0c;值越大&#xff0c;越不纯&#xff0c;相反值越小&#xff0c;代表集合纯度越高。信息增益反映的是给定条件后不确定性减少的程度。每一次对决策树进行分叉选取属性的时候&#x…

网络计划--时间参数的计算和优化

根据网络图的基本概念和原则绘制出网络图之后&#xff0c;我们可以计算网络图中有关的时间参数&#xff0c;主要目的是找出关键路线&#xff0c;为网络计划的优化、调整和执行提供明确的时间概念。如下图中从始点①到终点⑧共有4条路线&#xff0c;可以分别计算出每条路线所需的…

使用maven搭建父子工程项目

创建父子工程&#xff0c;可以通过父工程来引入jar&#xff0c;定义统一的版本号等。更方便对整个项目的jar包实现统一化管理&#xff0c;让项目的层次更加清晰。一、创建父工程第一步&#xff1a;file–>new–>project–>maven默认使用jdk1.8&#xff0c;不引入任何j…

音视频基础之视频主要概念

视频主要概念 **视频码率&#xff1a;**kb/s&#xff0c;是指视频文件在单位时间内使用的数据流量&#xff0c;也叫码流率。码率越大&#xff0c;说明单位时间内取样率越大&#xff0c;数据流精度就越高。 **视频帧率&#xff1a;**fps&#xff0c;通常说一个视频的25帧&…

ur3+robotiq ft sensor+robotiq 2f 140配置rviz仿真环境

ur3robotiq ft sensorrobotiq 2f 140配置rviz仿真环境 搭建环境&#xff1a; ubuntu: 20.04 ros: Nonetic sensor: robotiq_ft300 gripper: robotiq_2f_140_gripper UR: UR3 在安装sensor和gripper之前&#xff0c;先简单配置一下UR机械臂的仿真环境&#xff0c;可参考这篇博…

jenkins下载与简单使用

1.jenkins下载 因为我仍然使用的是jdk1.8进行开发&#xff0c;所以我下载的是jenkins2.332.1版本&#xff08;jenkins2.346.1版本在2022年末不再支持java8&#xff0c;如果项目使用的是jdk11可以继续使用该jenkins版本&#xff09;&#xff0c;更多版本下载请点击jenkins下载 …

ADRC自抗扰控制总结

目录 前言 1.ADRC形式 1.1形一 1.2形二 2.被控对象 3.仿真分析 3.1仿真模型 3.2仿真结果 4.学习问题 前言 前面的3篇文章依次介绍了微分跟踪器TD、状态观测器ESO和非线性状态误差反馈NLSEF三部分内容&#xff0c;至此ADRC的结构已经介绍完毕&#xff0c;现在对分块学习…

pytorch零基础实现语义分割项目(四)——模型训练与预测

模型训练与预测项目列表前言损失函数one_hotDice LossFocal Loss模型参数与训练预测项目列表 语义分割项目&#xff08;一&#xff09;——数据概况及预处理 语义分割项目&#xff08;二&#xff09;——标签转换与数据加载 语义分割项目&#xff08;三&#xff09;——语义…

JVM系统优化实践(1):JVM概览

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e;这是多年之前做过的学习笔记&#xff0c;今天再翻出来&#xff0c;觉得仍然是记忆犹新。「独乐乐不如众乐乐」&#xff0c;就拿出来分享给「众乐乐」吧。目前大多…

用户画像——如何构建用户画像系统

为什么需要用户画像 如果你是用户,当你使用抖音、今日头条的时候,如果平台推荐给你的内容都是你感兴趣的,能够为你节省大量搜索内容的时间。 如果你是商家,当你投放广告的时候,如果平台推送的用户都是你的潜在买家,能够使你花更少的钱,带来更大的收益。 这两者背后都…

KeePass敏感信息明文传输漏洞复现 (CVE-2023-24055)

一、漏洞描述 漏洞简述 KeePass 是一款免费的开源密码管理器&#xff0c;可帮助您以安全的方式管理您的密码。您可以将所有密码存储在一个数据库中&#xff0c;该数据库由一把万能钥匙锁定。因此&#xff0c;您只需记住一个主密钥即可解锁整个数据库。数据库文件使用目前已知…

面试个3年自动化测试,测试水平一言难尽。。。。

公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。 一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。 看简历很多都是3年工作经验&#xff0c;但…

中间件安全—Apache常见漏洞

中间件安全—Apache常见漏洞1.Apache常见漏洞1.1.Apache介绍1.2.Apache HTTPD 换行解析漏洞&#xff08;CVE-2017-15715&#xff09;1.2.1.漏洞介绍1.2.2.漏洞环境1.2.2.1.运行漏洞环境1.2.2.2.访问漏洞环境1.2.3.漏洞复现1.2.3.1.拦截1.2.3.2.添加换行1.2.3.3.访问文件1.3.Apa…

steam搬砖信息差项目,新手1周拿到结果!

项目具体是什么呢&#xff1f; 项目简单概括通过选品软件自动分析出此商品国内外商品价格&#xff0c;计算出利润率&#xff0c;选择出有利润销量好的商品&#xff0c;在以最低价格上架到国内buff的平台里&#xff0c;既能快速的卖出&#xff0c;还能获利。 主要利润在于商品…

在Vue.js中应该避免的三件事

1. 尽量避免使用行内事件代码(inline script) 这是一个行内事件代码 的例子 <div click"alert(hello world); doSomething();" />这种代码虽然第一次写起来很简单&#xff0c;但是很容易出bug。这样做有两个缺点。 VS Code 无法检查行内事件代码的错误 VS …

移动WEB开发五、响应式布局

零、文章目录 文章地址 个人博客-CSDN地址&#xff1a;https://blog.csdn.net/liyou123456789个人博客-GiteePages&#xff1a;https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee&#xff1a;https://gitee.com/bluecusliyou/TechLearnGithub&#xff1a;https:…

Dubbo之SpringBoot启动源码详解

需要前置知识&#xff0c;了解spring源码&#xff0c;springboot自动加载机制等 DubboBootstrap启动 详细信息可看 学习Dubbo源码需要了解的基础内容源码详解 DubboBootstrap 启动所需要的信息 添加应用程序配置添加注册中心配置添加协议配置添加服务配置启动 SpringBoot启…

音视频基础之音频编码原理简介

一&#xff1a;隐蔽信号 数字音频信号如果不加压缩地直接进行传送&#xff0c;将会占用极大的带宽。例如&#xff0c;一套双声道数字音频若取样频率为44.1KHz&#xff0c;每样值按16bit量化&#xff0c;则其码率为&#xff1a; 244.1kHz16bit1.411Mbit/s 如此大的带宽将给信号…

电商数据查询平台:母婴行业妈妈用品全网热销,头部品牌格局初现

以往&#xff0c;奶粉、纸尿裤这类产品基本就代表了整体母婴市场中的消费品。而如今&#xff0c;随着母婴行业的高速发展和消费升级&#xff0c;母婴商品的种类日益丰富&#xff0c;需求也不断深入。 在京东平台&#xff0c;母婴大品类中除了包含婴童相关的食品&#xff08;奶粉…