百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

多线程Qt下的八条规则 qt多线程处理数据

liebian365 2024-10-17 14:00 6 浏览 0 评论

相信资深Qter都认识Giuseppe D’Angelo,这位有着二十多年Qt开发经验,Qt源码行数贡献的最多的开发者之一,同时也是Qt项目的审批者,所说话的份量不言而喻。

原文作者: 朱塞普 D 安吉洛(Giuseppe D’Angelo

多线程一直是一个老生常谈的话题,而Qt作为C++生态非常重要的一环,熟练使用多线程是必备的技能。

Qt中封装了很多多线程的轮子,我们在日常开发中,除了要学会怎么用之外,如何用好才是关键。

下面来看一下可以代表Qt官方的Giuseppe D’Angelo是如何告诫大家的。

尽管多线程的概念看起来非常简单,但在日常编码中,使用多线程总会遇到难以复现和追踪的恶心BUG。这导致我们使用多线程写出可靠代码是非常困难的。接下来让我们深入了解一下,为什么会出现这种状况。

首先你需要对框架底层、编程语言、编译器的有深层次的理解,这样你才能知道如何避免线程高发问题;其次,你还要理解同步原语,使用合适的设计模式来编写多线程代码,只有这样才能使多业务在所有条件下正常执行;最后,你还要学会使用调试工具来调试多线程,只有这样你才能发现多线程内部难以复现的BUG。

当涉及到Qt多线程后,尤其需要了解你的框架和设计模式。Qt能让你写出令人惊奇的多线程程序,也能让你开枪打自己的脚。多年的Qt框架、Qt客户端多线程BUG查找和修复经验磨练了我们多线程编码水平,这里有几条我们总结出来的顶级信条,它可以让你避免多线程常见问题,可以让你的程序在第一时间正常运行。

1. 避免使用QThread::sleep()

尽管 QThread::sleep() 是一个让你的线程休眠的API,如果你使用了它,那么你应该重新学习一下事件驱动设计。如果你将“多线程休眠”改为“多线程事件等待”(或者最好是不使用多线程),那么你将会节省巨大的系统资源,不然这些资源就被空转的线程浪费了。QThread::sleep() 用作计时器,也是一个糟糕的设计,因为从线程休眠到返回控制的这段时间,是很难受到控制的。理论上讲,当进程终止时,休眠的线程也会导致问题。前台线程可以阻止程序终止,直到他们被唤醒,而后台线程永远不会唤醒前台线程,结果就是程序的清理终止一直被阻止。

2. 禁止子线程操作GUI

QtGUI 操作不是线程安全的,所以非主线程外一切线程对GUI的操作都是不安全的。这就意味着窗口小部件、QtQuickQPixmap,以及其他任何类的对象都不能在非主线程操作GUI。当然也有些特例:GUI函数只操作数据,不触及窗口UI管理,这是可以被子线程调用的,比如 QImageQPainter。但是依旧要小心,像 QBitmapQPixmap 这些类依旧是线程不安全的。可以查询每个 API 的官方文档:如果你没有看到 可重入(reentrant 标识,那么在子线程的一切调用都是不安全的。

3. 不要阻塞主线程

不要在主线程调用任何不明确阻塞时间的函数(比如 QThread::wait() ),因为这些函数会使你主线程的事件循环暂停,造成UI冻结。如果你的主线程阻塞时间足够长,那么操作系统会认为你的程序冻结,会询问你要不要干掉它(鲲哥: Windows常见于 “窗口未响应” )。不管是无限阻塞还是长时间阻塞主线程,对程序来说都是很搓的做法。

4. 一定要在拥有QObjects所有权的线程上对其进行销毁

Qt从设计上就不允许在非拥有QObject 所有权的线程上对其进行销毁,这意味这,一个QThread在销毁之前,它所掌握的所有QObject必须先销毁。如果没有这么做,那么很可能引发数据完整问题,比如常见的内存泄露和进程 crash
那么如何确定销毁
QObject 的线程就是拥有其所有权的线程呢?我们可以将其创建为在QThread::run() 方法函数内执行的自动变量,关联QThread::finished() 信号与QThread::deleteLater() 槽函数;也可以通过moveToThread()QObject 移动到其他线程进行延迟析构。注意,一旦你把QObject从原来拥有它的线程移动到新线程后,你就不能用原来的线程操作它了,因为它的所有权属于新的线程了。

5. 线程同步的时候,不要相信自己的直觉

一种非常常见的设计方式就是一个线程把自己的运行状态,通过布尔变量的形式传递给监控线程,供其监控。一个简单的数据结构,一个线程写,另一个线程读,这样看起来是不需要做同步保护,因为我们能确保最终能读到它,是这样吗?直觉上看起来是没问题的,实际上就是这么简单一个案例也是线程不安全的。
C++标准规定线程同步是强制性的,任何超纲的行为都会导致未定义行为(
UB)。如果你并没有做线程同步,即使是一个简单案例,也会给你制造问题。事实上,Linux内核发现的一些严重BUG就是这么产生的。我们最应该做的不是过度思考安全与否,假设有一个被多个线程同时操作的数据,即使这个数据看起来多么人畜无害,产生问题的几率有多么小,我们一定要用合适同步手段来保护这个数据。

6. 假设QObject是不可重入的

一个函数能被不同的线程不同数据同时访问,且不需要任何同步方法保护,那么这个函数就是可重入的。Qt官方文档显示QObject是可重入的,但实际上却有很多警告:

  • 基于事件的类型是不可重入的(定时器、socket等等)
  • 假设某一QObject正在其归属的线程中进行事件派发,如果你在另一个线程操作它,这就可能会导致竞争。
  • 从属于同一父子关系树的所有QObject对象,必须在同一个线程进行处理。
  • 删除QThread 对象之前,必须先把其拥有的所有QObject对象干掉。
  • 你必须在一个对象归属的线程里面使用对这个对象使用 moveToThread()

为了避免以上所有特殊场景,最简单的方法就是认为QObject 是不可重入的。事实上,这就意味着你必须在QObject 所属的线程上操作它。这也会让你远离所有可能会出现问题,同时也是难以察觉的场景。

7. 避免往QThread增加槽函数

因为QThread 对象和创建他们的线程存在关联(或许不存在关联),但在子线程使用信号槽的时候,很容易产生问题。尽管子线程可以使用槽函数,当需要规避大量难以察觉的缺陷时,我们建议你不要这么做。
如果你不需要重写
QThread::run() 函数,那么请不要从QThread 派生子类。只需要创建一个QThread 对象即可,这样你就能避免槽函数问题(更多请关注作者博客的其他博文)。

8. 请使用C++标准库,因为更好用

最后,不管是C++标准库,还是第三方库,在多线程方面都比Qt更具特色。它们包含Qt没有的功能——并行算法、协程、锁存器、内存屏障、原子智能指针、任务延续、executors、并发队列、分布式计数器等等。
Qt的多线程在一些场景下仍然好用,比如C++标准库里面没有线程池,但是Qt就有。好消息就是C++标准库和Qt完美兼容,你可以自由地将标准库引入你的代码里面。事实上,除非你要用线程操作
QObject 对象才必须用到QThread,不然使用C++标准库还是Qt的多线程库,依赖于你个人喜好。

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: