线程和进程是程序员老生常谈的问题了,任何阶段的程序员都不敢轻视他。 事实上大部分程序员并没有系统化的学习过,也有很多人并没有机会好好运用它。所以,如果拉一个工作多年的程序员讨论,对方未必能说出个所以然。 本文是 Linux 下 C++ 多线程编程开发的系列文章之首,在介绍具体编程实现而言,先讲讲它的基础概念,并给予通俗化的解释,并在文章最后给出一个开放的思考题。 线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。1 上面的定义来自于百度百科,定义的很准确,但同时也很抽象。 线程可一看作是轻量级的进程,它依赖于进程。 所以,搞清楚线程前,我们先来看看进程是什么。 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。2 上面的定义同样来自于百度百科,定义非常准确,但同时也非常抽象。 所以,为了很好的搞明白线程和进程,我尝试用一些通俗的比喻来解释。 我们把整个计算机比喻成一个公司,公司由一些基本的单元组成: 公司要正常运作,依赖于制度流程。 制度流程可以等同于什么呢? 操作系统 正因为规章制度流程的存在,公司的软硬件、设备资源可以协调给每一个部门。 如果公司十分庞大,组织复杂,那么部门就是最基础的单元。 也就是说 进程可以看做是部门 部门依法使用公司规定的软硬件资源,进程在操作系统的只能也是类似。 上面的定义中有讲到,现代操作系统中,进程是一个容器。 每个进程拥有自己的独立空间,相互间不干扰。 这个好理解,现实中,每个部门有自己的软硬件和员工,一般情况下相互不干涉。 那么线程呢? 线程依赖于进程,而不能独立存在。 线程是最基本的执行单元,对比现实生活就是是部门中的员工。 仔细体会一下。 部门提供资源,员工干活。 进程提供资源,线程干活。 但如果公司有重大决定,它一般不会直接针对个人,而是下发到部门,控制部门这一层就好了。 如果操作系统根据事情轻重缓急,它也会直接和进程交涉,进程受它的调度。 一个进程一般有一个或者多个线程。 同一个进程中的线程可以共享进程的数据。 但同时,其实线程也有自己的内存模型。 线程开发中可以利用 TLS(Thread-Local Storage,线程局部存储)来实现线程独有的内存数据不被同一个进程其它线程干扰,每一个线程维护一份共享变量的拷贝,所以基于拷贝上的操作不会影响其它线程。 那么,线程和进程有什么区别呢? 进程是资源分配的基本单位,线程是调度的基本单位。 这是一句名言,很好地概括了两者的区别。 用一句话来概括就是: 进程对应操作系统,线程对应 CPU。 我们常说的任务调度,其实通常讲 CPU 通过时间片轮转,调度线程。 也并不是说进程不能调度,是说线程更轻量化。 如果要了解更深入的话,可以带入到下一个问题。 我们用线程,提起的很多的就是多线程。 多线程的目的就是并行开发。 大家讲多线程的时候,总喜欢讲车站买票的例子。 现在有 10 个人买票。 如果这个工作效率很低,那么我们可以这样: 增加类似的窗口,提供并行服务。 并行的目的是为了加速。 多线程开发也是基于上面 2 个原因: 并行就是,我要一边听歌,一边写文章。 加速就是,下载一个文件单线程太慢了,多个线程一起下载就能加速。 那是不是线程越多越好呢? 答案是否定的。 多线程能干的事情多进程也能干。 但两者都不是越多越好。 这涉及到上下文切换的问题。 上下文的英文单词是 Context。搞 Android 和 Java Web 开发的应该再熟悉不过了,它代表的是任务的同一语境。 上下文切换就是任务切换,可能是进程的切换也可能是线程的切换。 上下文的切换是一个很深的话题,我们大可不必在此过多讨论,我们可以简单看待: 上下文的切换就是任务状态的保存与恢复。 当 CPU 挂起一个任务时,它需要将 CPU 寄存器里面的信息保存到任务的堆栈当中,然后从下一个任务的堆栈中读取对应的 CPU 寄存器信息并恢复,那么下一个任务就可以执行了。 图片来源于网络3 但上下文切换的开销很昂贵,它有大量的工作需要处理,比如寄存器和内存页表的存储和恢复、内核数据结构的更新等等。 所以,线程并不是越多越好,因为线程越多,上下文切换越频繁,极端情况下效率不升反降。 并且,进程的上下文切换比线程开销的要大。 注意:在同一个进程中,线程的切换不会引起进程的切换,不同进程中,线程的切换会引起进程的切换。 所以,回到问题什么时候用进程什么时候用线程这个问题上来,一般认为: 相互独立的任务用进程 因为内存独立的原因,资源相互不干扰,比如播放音乐用一个进程,图像绘制用一个进程。音乐出故障了,图像还能正常绘制。如果用线程的话,单线程发生故障可能导致整个进程一起被干掉。 2.相关性高的并行需求用线程 因为线程上下文切换开销小,所以同一个任务或者同一个业务逻辑的代码可以尝试用线程开发。 线程和进程的基本差别上面内容介绍的差不多了,下面提一些线程开发中常出现的基础概念。 用户态线程指的是用户层面自己创建的线程,自己管理生命周期,包括创建、切换、销毁。比如,最近流行的协程就属于此,一般通过线程库实现。 内核态线程指的是由操作系统的内核管理生命周期的线程,如用 pthread 创建的线程。 POSIX(Portable Operating System Interface of UNIX)是可移植操作系统接口,定义了操作系统应该为应用程序提供的接口标准。 什么意思呢? 操作系统有很多种,有些编程语言可以跨平台开发,有些则不能。 比如,Android 成立之初就选用 Java,原因就是 Java 跨平台,所以那些做 Java 开发的工程师可以很快投入到新的领域。但是 Java 的跨平台是建立在虚拟机上,虚拟机屏蔽了操作系统的不同,提供了统一的 API,但一定程度上牺牲了性能。我们很多年感觉的 Android 卡,和这有很大关系。 而 POSIX 意在获得操作系统源码级的 API 支持。 并且,POSIX 标准中定义了进程和线程相关标准。 Linux 是支持 POSIX 标准的,我们用 pthread 创建线程就属于此。 在 Linux 开发中,线程的实现可以通过系统调用。 但系统调用太麻烦了,一般用线程的封装好的线程库,目前常用的有: 文章最后,抛出一个问题。 我们知道,多线程开发是为了并行。 并行是通过 CPU 时间片调度而来。 也有同学知道,所谓并行其实只是看起来并行。 那问题是: 可以串行的任务,非要人为并行吗? https://baike.baidu.com/item/%E7%BA%BF%E7%A8%8B/103101?fr=aladdin ↩︎ https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B/382503?fr=aladdin ↩︎ https://baike.baidu.com/pic/%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2/4842616/0/37d12f2eb9389b504fc24c9c577df2dde71191efc0ee?fr=lemma&ct=single#aid=0&pic=37d12f2eb9389b504fc24c9c577df2dde71191efc0ee ↩︎什么是线程?
什么是进程?
进程和线程有什么区别?
什么时候用线程和进程?
窗口:@-@-@-@-@-@-@-@-@-@
窗口:@-@-@-@- 窗口:@-@- 窗口:@-@-@-@-
上下文切换
线程开发的基础概念
用户态线程和内核态线程
POSIX 标准
线程库
思考题
线程 A: ++ + + + 线程 B: - - -- - CPU : ++-+-+--+-
引用
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算