Qt系统相关——QThread

embedded/2024/9/24 5:43:25/

文章目录

    • QThread的API
    • 使用示例
    • 客户端多线程应用场景
    • 互斥锁
      • QMutex
      • QMutexLocker
      • QReadWriteLocker、QReadLocker、QWriteLocker
    • 条件变量和信号量

QThread的API

Qt中的多线程和Linux中的线程,本质上是一个东西

Linux线程概念

Linux多线程——线程控制

Linux多线程——互斥锁

Linux多线程——生产消费者模型

QThread:

  • 要创建线程,需要创建这个类的实例
  • 创建线程时,需指明线程入口函数
  • 创建QThread的子类,重写了其中的run方法,起到指定入口函数的方式(多态)

Tips:

这种方式在C++中并不常见,相比之下std::thread直接指定回调方式更常见

因为C++比较追求性能,多态机制可能导致运行时的额外开销(查询函数表,找到对应执行函数再执行)

但是对应客户端开发,对性能的要求,并没有那么的高

API说明
run()线程入口函数
start()通过运行run()开始执行线程
(该操作是真正调用系统API创建线程)
currentThread()获取当前线程的指针
isRunning()如果线程正在运行返回true,否则返回false
sleep()、msleep()、usleep()线程休眠,单位秒/毫秒/微妙
wait()线程阻塞,功能和pthread_join类似
terminate()终止线程执行。
线程可以立即终止,也可以不终止,取决于操作系统的调用
finished()线程结束发出的信号,可通过该信号实现线程的清理工作

使用示例

基于定时器的倒计时程序

创建QThread子类:

image-20240923211212409

thread.h

#ifndef THREAD_H
#define THREAD_H#include <QWidget>
#include<QThread>
class Thread : public QThread
{Q_OBJECT
public:Thread();//重写父类run方法void run();
signals://只需写函数声明, 定义Qt自动生成void notify();
};#endif // THREAD_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include"thread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handle();private:Ui::Widget *ui;Thread thread;
};
#endif // WIDGET_H

thread.cpp

#include "thread.h"Thread::Thread()
{}void Thread::run()
{//针对时间进行计时,每过一秒,通过信号槽通知主线程更新界面for(int i = 0; i < 10; i++){sleep(1);//发生信息emit notify();}
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//连接信号槽connect(&thread, &Thread::notify, this, &Widget::handle);//启动线程thread.start();
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{int value = ui->lcdNumber->intValue();value--;ui->lcdNumber->display(value);
}

如果多个线程同时对界面进行修改,就会导致界面出错。

Qt直接一刀切,针对控件的任何修改,都在主线程中执行。

运行示意图:

image-20240923212827943

客户端多线程应用场景

在服务器开发的角度,多线程主要是充分利用多核CPU的计算资源,达到更高的效率。

而对于客户端,对效率要求并不是特别高,如果追求效率,把CPU计算资源吃完,会导致系统卡顿,这用户体验是很差的。

在客户端中,多线程主要是用于一些耗时的等待IO的操作,避免主线程卡死。

比如说客户端向服务端上传/下载较大的文件

这种密集的IO操作会使程序被系统阻塞挂起,一旦进程被挂起了,此时用户的操作就无法响应了。

因此使用单独的线程来处理这种密集的IO操作,就算挂起,也是挂起的这个线程,并不会影响主线程。

互斥锁

QMutex

谈到线程,必定绕不开线程安全问题,最通用的手段就是加锁,QMutex类就是Qt封装的互斥锁。

image-20240923215302391

上面这种情况就是线程安全问题,采取加锁,让线程串行执行

锁也是公共区的,只有一把锁

image-20240923215537861

QMutexLocker

C++11引入了std::lock_guard,智能锁RAII机制,这样能避免抛出异常或者忘记释放锁导致的问题。

Qt参考过来了,叫做QMutexLocker

image-20240923220111369

Tips:

Qt的锁和C++的锁,本质上都是封装系统提供的锁

虽然可以用C++的锁锁住Qt的线程,但是不建议。

QReadWriteLocker、QReadLocker、QWriteLocker

  • QReadWriteLocker读写锁,用于控制读和写的并发访问
  • QReadLocker用于读操作上锁,允许多个线程共享资源
  • QWriteLocker用于写操作上锁,一次允许一个线程写数据

条件变量和信号量

Qt当中的条件变量和信号量,与Linux当中的概念一模一样,只不过是接口不一样而已。

多个线程的调度是无序的,为了一定程度干预执行顺序,引入条件变量。

QWaitCondition

  • wait等待
  • wake唤醒
  • wakeAll唤醒全部

QSemaphore

  • acquire获取信号量
  • release释放信号量

http://www.ppmy.cn/embedded/115932.html

相关文章

Python 实现图形学光栅化的扫描线算法

目录 Python 实现图形学光栅化的扫描线算法引言扫描线算法简介几何概念Python 实现1. 类结构设计2. 代码实现 代码详解使用示例扫描线算法的优点总结 Python 实现图形学光栅化的扫描线算法 引言 光栅化是图形学中非常重要的一个阶段&#xff0c;它将几何描述转换为图像描述&a…

npm run build报Cannot find module错误的解决方法

目录 一、问题描述二、解决方法一、问题描述 执行 npm run build 报 Cannot find module 错误: npm run build> vite-vue3@0.0.0 build > vite buildfailed to load config from D:\Workspaces\PhpProjects\jjj-edu-master\jjj_edu_admin\vite.config.js error during…

R语言 基础笔记 2

起因&#xff0c; 目的: 偶然看到一个新的教程&#xff0c; 有些知识点&#xff0c;以前没见过&#xff0c;不熟悉&#xff0c; 现在遇到了&#xff0c;记录一下。 基础数据类型 2L&#xff0c; 表示整数 3 ^ 2, 表示求幂 class(a) 查看 类 typeof(a) 查看基本数据类型 s…

代码随想录打卡Day41

最近事情好多。。全堆一块了&#xff0c;今天先写两题吧&#xff0c;剩下一题明天解决。 121. 买卖股票的最佳时机 这道题纯不会&#xff0c;不知道该怎么构造dp数组&#xff0c;更不知道dp数组的含义&#xff0c;看完讲解以后感觉这样的dp数组构造还挺巧妙的&#xff0c;第一…

gitlab默认克隆地址的修改

目录 1.找到opt/gitlab/embedded/service/gitlab-rails/config目录&#xff0c;打开gitlab.yml 2.修改地址和端口 3.重启gitlab 1.找到opt/gitlab/embedded/service/gitlab-rails/config目录&#xff0c;打开gitlab.yml cd /opt/gitlab/embedded/service/gitlab-rails/confi…

在Android开发中可以用到的Ui控件有哪些?

目录 1. 文本控件 2. 按钮控件 3. 选择控件 4. 布局控件 5. 图像控件 6. 列表控件 7. 对话框和提示 8. 菜单控件 9. 工具栏和导航控件 10. 进度控件 11. 时间与日期控件 12. 其他控件 13. 高级控件 14. 自定义控件 15. 其他 总结&#xff1a; 在 Android 开发中…

JAVA基础:HashMap底层数组容量控制,TreeMap底层存取机制,位运算符,原码反码补码

List常用实现类 List集合常用的实现类有3个 &#xff0c; ArrayList , LinkedList , Vector ArrayList 类似于我们之前的ArrayBox 底层使用数组存储元素&#xff0c; 插入删除的效率低&#xff0c;检索的效率高 当底层数组存储容量不足时&#xff0c;会进行扩容&#xff0c;…

Redis 命令:

1.通用键命令 set key value&#xff1a;设置指定键的值。get key&#xff1a;获取指定键的值。del key [key ...]&#xff1a;删除一个或多个键。expire key seconds&#xff1a;设置键的过期时间&#xff08;以秒为单位&#xff09;。ttl key&#xff1a;查看键的剩余存活时间…