线程的基础知识

什么是线程?

线程和进程一样,都是并行的。那么线程和进程有什么不同呢?当你在电子表格上进行计算时,可能还有一个媒体播放器在同一台桌面上播放你最喜欢的歌曲。下面是两个并行工作的进程的例子:一个运行电子表格程序;一个运行着媒体播放器。多任务处理是一个众所周知的术语。仔细看一下媒体播放器就会发现,在一个进程中又有一些事情同时发生。当媒体播放器向音频驱动发送音乐时,用户界面及其所有的铃声和哨声都在不断更新。这就是线程的作用——在单个进程中实现并发

那么并发是如何实现的呢?在单核cpu上并行工作是一种错觉,有点类似于电影中移动图像的错觉。对于进程来说,在很短的时间后中断处理器在一个进程上的工作就会产生错觉。然后处理器继续下一个进程。为了在进程之间进行切换,当前程序计数器被保存,下一个处理器的程序计数器被加载。这还不够,因为需要对寄存器、特定体系结构和特定于操作系统的数据进行同样的处理。

正如一个CPU可以为两个或多个进程提供动力一样,也可以让CPU运行在单个进程的两个不同代码段上。当一个进程启动时,它总是执行一个代码段,因此该进程有一个线程。但是,程序可能决定启动第二个线程。然后,在一个进程中同时处理两个不同的代码序列。并发是通过反复保存程序计数器和寄存器,然后加载下一个线程的程序计数器和寄存器,在单核cpu上实现的。在活动线程之间循环不需要来自程序的协作。当切换到下一个线程时,线程可能处于任何状态。

前CPU设计的趋势是拥有多个内核。典型的单线程应用程序只能使用一个核心。但是,具有多个线程的程序可以分配给多个核,从而使事情以真正并发的方式发生。因此,将工作分配到多个线程可以使程序在多核cpu上运行得更快,因为可以使用额外的核。

GUI线程和工作线程

前所述,每个程序在启动时都有一个线程。这个线程称为“主线程”(在Qt应用程序中也称为“GUI线程”)。Qt GUI必须在这个线程中运行。所有小部件和几个相关类,例如QPixmap,都不能在辅助线程中工作。辅助线程通常被称为“工作线程”,因为它用于从主线程分担处理工作。

同时访问数据

个线程都有自己的栈,这意味着每个线程都有自己的调用历史和本地变量。与进程不同,线程共享相同的地址空间。下图显示了线程的构建块在内存中的位置。非活动线程的程序计数器和寄存器通常保存在内核空间中。每个线程都有一个共享的代码副本和一个单独的栈。

如果两个线程有一个指向同一对象的指针,那么两个线程可能会同时访问该对象,这可能会破坏对象的完整性。很容易想象,当同一对象的两个方法同时执行时,可能会出现许多错误。

有时需要从不同的线程访问一个对象;例如,当生存在不同线程中的对象需要通信时。由于线程使用相同的地址空间,所以线程交换数据要比进程更容易更快。数据不必序列化和复制。传递指针是可能的,但必须严格协调哪个线程接触哪个对象。必须防止在一个对象上同时执行操作。有几种方法可以实现这一点,下面描述了其中一些方法。

那么可以安全地做什么呢? 只要其他线程没有对它们的引用并且对象与其他线程没有隐式耦合,则可以在该线程内安全地使用在线程中创建的所有对象。 当实例之间共享数据时,例如静态成员,单例或全局数据,可能会发生这种隐式耦合。 熟悉线程安全和可重入的类和函数的概念。

使用线程

线程基本上有两种用例:

  • 通过使用多核处理器来加快处理速度。
  • 通过卸载长时间持续处理或阻塞调用给其他线程,保持GUI线程或其他时间关键线程响应。

何时使用线程的替代方法

开发人员在使用线程时需要非常小心。 启动其他线程很容易,但是很难确保所有共享数据保持一致。 问题通常很难发现,因为它们可能仅偶尔出现一次或仅在特定的硬件配置上出现。 在创建线程来解决某些问题之前,应考虑可能的替代方法。

Alternative 简介
QEventLoop::processEvents() 在耗时的计算过程中重复调用QEventLoop :: processEvents() 可防止GUI阻塞。 但是,此解决方案不能很好地扩展,因为根据硬件的不同,对processEvents() 的调用可能发生的次数过多或不足。
QTimer 有时可以使用计时器方便地完成后台处理,以安排将来某个时刻执行插槽。 没有更多事件要处理时,间隔为0的计时器将超时。
QSocketNotifier QNetworkAccessManager QIODevice::readyRead() 这是具有一个或多个线程的替代方法,每个线程在慢速网络连接上都具有阻止读取的功能。 只要可以快速执行响应大量网络数据的计算,这种响应式设计就比线程中的同步等待更好。 响应式设计比线程设计更不容易出错并且更节能。 在许多情况下,还可以提高性能。

通常,建议仅使用安全且经过测试的路径,并避免引入临时线程概念。 QtConcurrent模块提供了一个简单的接口,用于将工作分配到所有处理器内核。 线程代码完全隐藏在QtConcurrent框架中,因此您不必关心细节。 但是,当需要与正在运行的线程进行通信时,不能使用QtConcurrent,并且不应将其用于处理阻塞操作。

您应该使用哪种Qt Thread技术?

有关对Qt进行多线程处理的不同方法的介绍,以及有关如何选择这些方法的指南,请参见Qt中的多线程技术相关内容( Multithreading Technologies in Qt)。

Qt线程基础

以下各节描述了QObjects如何与线程交互,程序如何安全地从多个线程访问数据以及异步执行如何在不阻塞线程的情况下产生结果。

QObject和线程

上所述,开发人员在从其他线程调用对象方法时必须始终小心。QObject的线程亲和性不会改变这种情况。Qt文档将几个方法标记为线程安全的。postEvent()是一个值得注意的例子。线程安全的方法可以从不同的线程同时调用。

通常没有并发访问方法的情况下,在并发访问发生之前,调用其他线程中对象的非线程安全方法可能要工作数千次,从而导致意外行为。编写测试代码并不能完全确保线程的正确性,但它仍然很重要。在Linux上,Valgrind和Helgrind可以帮助检测线程错误。

保护数据的完整性

在编写多线程应用程序时,必须特别注意避免数据损坏。有关如何安全使用线程的讨论,请参阅同步线程(Synchronizing Threads)。

处理异步执行

获得工作线程结果的一种方法是等待线程终止。然而,在许多情况下,阻塞等待是不可接受的。阻塞等待的替代方法是使用已发布的事件或排队的信号和槽异步结果交付。这将产生一定的开销,因为操作的结果不会出现在下一个源代码行上,而是出现在源文件中其他位置的槽中。Qt开发人员习惯于使用这种异步行为,因为它与GUI应用程序中使用的事件驱动编程非常相似。

示例

Qt提供了几个使用线程的示例。有关简单示例,请参阅QThread和QThreadPool的类。有关更高级的示例,请参见线程和并发编程示例页面(Threading and Concurrent Programming Examples)。

更深入的研究

线程是一个非常复杂的主题。Qt提供的线程类比我们在本教程中介绍的要多。以下材料可以帮助你更深入地了解这个主题:

  • Qt文档中的线程支持是进入参考文档的一个很好的起点。
  • Qt附带了几个QThread和QtConcurrent示例。
  • 有几本好书描述了如何使用Qt线程。最广泛的介绍可以在Mark Summerfield和Prentice Hall的《高级Qt编程》一书中找到——大约500页中的70页涵盖了QThread和QtConcurrent。

Qt 线程(00):线程基础知识【官翻】相关推荐

  1. 进程、线程等操作系统基础知识

    今天在班级群里面水群时出现了一个严重的错误,然后就和老师发生了较为激烈的辩论,最后却发现我和老师的观点根本就不是针对同一个问题的,而我确实有一个知识点错了,收获很大,下面我也会提出这个知识点.平时和老 ...

  2. 线程安全性的基础知识

    "共享"意味着变量可以由多个线程同时访问,而"可变"则意味着变量的值在其周期内是可以发生变化的. 一个对象是否是线程安全的,取决于它是否被多个线程访问. 当多个 ...

  3. 【Android 基础知识】翻页类视图 ViewPager

    文章目录 1.翻页视图 ViewPager 2.翻页标题栏 PagerTitleStrip/PagerTabStrip 1.翻页视图 ViewPager 对于 ViewPager 来说,一个页面就是一 ...

  4. 【QT】QSS美化——基础知识

    目录 一.辅助工具 二.QSS加载方式 三.QSS选择器类型 3.1 通配选择器 3.2 类型选择器 3.3 属性选择器 3.4 类选择器 3.5 ID选择器 3.6 后代选择器 3.7 子选择器 3 ...

  5. Solidity 基础知识

    Solidity 基础知识 官网:Solidity 版本设置 // SPDX-License-Identifier:MIT 表示身份协议 // ^0.8.7 表示当前代码支持 0.8.7 及以后 so ...

  6. VBA基础知识 提取超链接 批注转内容 工作簿内图片联动

    基础知识 官方文档:https://docs.microsoft.com/zh-cn/office/vba/api/overview/ 基本流程:尝试寻找最佳路径--文字记录--录制VBA--修改,写 ...

  7. 正则基础知识学起来很简单

    正则基础知识学起来很简单 第一.正则表达式,也称为模式表达式,它有自己一套完整编写规范. 正则表达式的用途:正则表达式主要是用来对字符串进行匹配.查找.替换和分割等操作. 第二.正则表达式主要是由四部 ...

  8. Qt 线程(06):线程和QObject【官翻】

    线程和QObject 前言 QThread继承了QObject. 它发出信号以指示线程已开始执行或完成执行,并且还提供了一些插槽. 更有趣的是,QObjects可以在多个线程中使用,发出调用其他线程中 ...

  9. JavaSE基础二十:Java 多线程(线程基础知识、Java 多线程、Java 实现多线程(继承 Thread 类、实现 Runnable 接口、实现 Callable 接口))

    本章目录 1.基础知识准备 2.Java 多线程概述 3.Java 实现多线程 3.1.继承 Thread 类 如何开启新线程 Thread 类常用方法 多线程中的同步 Thread 类同步方法 多线 ...

最新文章

  1. java简单通讯录的实现02person类_用java实现简单的小游戏(你一定玩过)
  2. php laravel 框架 APP_KEY 的作用
  3. 数论总结 (常用定理+ 模板)
  4. Java常用类之【八种基本数据类型】
  5. recurrence relation in parenthesis placing problem
  6. 河北计算机一级考试题库操作题,年河北计算机一级操作题题库及答案.doc
  7. DCMTK:将显示曲线导出到文本文件
  8. java加载dll UnsatisfiedLinkError: no mydll in java.library.path
  9. 百度地图gif图标_华为手机误删照片怎么找回?手机怎么快速制作GIF动图
  10. Android DownloadManager 的使用
  11. [蓝桥杯]PREV-12.历届试题_危险系数
  12. Linux文档内容查阅命令总结 - cat,tac,nl,more,less,head,tail,od
  13. 小米手机下载二维码APP
  14. 用Excel做数据地图
  15. 对数周期天线hfss建模_07 HFSS软件二次开发在对数周期天线设计中的应用
  16. 微博除夕日活达1.34亿 借阿里云化解流量洪峰
  17. Graph_Master(连通分量_D_Trajan缩点+dfs)
  18. 【I.MX6ULL】6ull 加载 linux 驱动模块失败
  19. [分享]加拿大渥太华市卡尔顿大学John W. Chinneck教授谈如何组织论文
  20. Java常用开源框架

热门文章

  1. python抢票12306源码_Python实现12306火车票抢票系统
  2. CV 领域的最美情话
  3. Java基础笔记(14)—— Java的基础类型和字节大小
  4. Pelican创建静态博客
  5. Oracle创建索引、视图SQL语句
  6. MySQL创建各种索引的SQL语句
  7. 人人AI(吴恩达系列)
  8. java爬取彩票数据_爬取彩票信息(有空试下)
  9. Android EditText 的属性
  10. Java算法题:两数之和