iOS 多线程系列 (一)

2020-11-03  本文已影响0人  卖馍工程师

现代计算机系统中,CPU作为计算机系统的运算控制核心,是信息处理、程序运行的最终执行单元。操作系统作为计算机的管理者,负责任务的调度资源的分配和管理,协调着各个硬件(如CPU、内存,硬盘、网卡等)有序的工作着。

在了解进程和线程之前,我们不妨先从操作系统开始。

一、操作系统

1.1 操作系统概念

操作系统是管理计算机硬件与软件资源计算机程序。作为计算机最基本也最为重要的”软件“系统,操作系统需要处理如管理与配置内存决定系统资源的供需的优先次序控制输入设备与输出设备操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。

从计算机用户的角度来说,计算机操作系统体现为其提供的各项服务;从程序员的角度来说,其主要是指用户登录的界面或者接口;如果从设计人员的角度来说,就是指各式各样模块和单元之间的联系。

1.2 操作系统发展的几个阶段

1.2.1 无操作系统阶段

最初的电脑没有操作系统,在这个阶段,计算机都是人工的去操作的,人们通过各种按钮来控制计算机,在操作的时候,每个用户都会独占这台计算机。并且计算机的CPU是等待人工去操作的,当用户进行输入和输出的时候,内存CPU都是空闲的。

因此,在没有操作系统的时代,计算机资源的利用率很低

1.2.2 批处理系统阶段

后来出现了汇编语言,操作人员通过有孔的纸带将程序输入电脑进行编译。
批处理系统阶段,计算机就无须再等待人工的输入了。因为这个时候用户会批量的导入任务,这样,用户在导入任务之后就可以离开,计算机就可以自动的去工作。

虽然在这个批处理系统里面,我们可以将任务批量的输入,但是这个时候计算机只能同时运行一个任务。也就是说,虽然任务是批处理输入的,但是计算机每次还是只能执行一个任务。

为了解决这一问题,在这个阶段提出了一个非常重要的概念,叫多道程序设计

多道程序设计

多道程序设计指的是在计算机内存中同时存放多个程序,并且这多个程序互相不干扰。 这里的多道程序在计算机的管理程序之下相互穿插运行,以此来提升计算机资源的利用率。

1.2.3 分时系统阶段

在这个阶段,最重要的设计就是人机交互的设计,在前面两个阶段,程序在执行的过程中,人是没有办法去干预的,在分时系统阶段,人机就可以进行交互了。并且,人可以实时的去调试程序,这个分时系统允许多个用户去共享这个计算机的资源,因此在这个阶段,计算的资源利用率大幅度提升。分时系统也是现在主流的系统。

1.3 操作系统的功能与意义

操作系统主要包括以下几个方面的功能 :

① 进程管理
其工作主要是进程调度,在单用户单任务的情况下,处理器仅为一个用户的一个任务所独占, 进程管理的工作十分简单。但在多道程序或多用户的情况下,组织多个作业或任务时,就要解决处理器的调度、分配和回收等问题 。
② 存储管理
分为几种功能:存储分配、存储共享、存储保护 、存储扩张。
③ 设备管理
分有以下功能:设备分配、设备传输控制 、设备独立性。
④ 文件管理
文件存储空间的管理、目录管理 、文件操作管理、文件保护。
⑤ 作业管理
负责处理用户提交的任何要求。

计算机的操作系统对于计算机可以说是十分重要的。

1.4 小结

在没有操作系统的时代,资源只属于当前运行的程序,且计算机只能运行一个程序,计算机资源利用率很低。

因为有了多道程序设计的概念,为了实现程序的共用,以及对计算机资源的管理,便有了操作系统。

二、进程与线程

为了使多个程序能并发执行,以提高资源的利用率和系统的吞吐量。进程也就出现了,进程的作用就是合理的隔离资源(因为有多道程序的概念,所以在计算机中就可能会有多个进程共同的使用某一个物理设备,比如存储器。那么进程在这里面就是发挥运行资源隔离的作用)、提升资源利用率

一个程序在运行过程中会涉及很多操作,利用 CPU 计算、通过磁盘 IO 进行数据传输等等,我们知道当程序在进行磁盘 IO 的时候,因为速度问题,会比较慢,所在在这个过程中 CPU 会空闲下来,这会造成资源的浪费,正因为引入进程,在 A 进程进行磁盘 IO 的时候,会让出 CPU 给 B 进程,合理地利用了 CPU 资源,使得程序之间可以并发执行。

2.1 进程

进程(Process)是计算机中具有一定独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是系统进行资源分配和调度的基本单位(有了多道程序的概念,操作系统就可以对每个程序进行资源的分配)。

从狭义上,可以将进程理解为正在运行的程序的实例,当一个程序进入内存运行时,系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。

下图为Mac系统下的活动监视器

从图片来看,每一个进程都占有 CPU内存能耗磁盘网络等资源。

每一个进程都有它自己的地址空间,一般情况下,进程由 3 个部分组成,分别是程序代码数据集、栈进程控制块(Process Control Block)。

各自的作用如下:

进程具有的特征:

2.2 线程

在早期的操作系统中并没有线程的概念,进程是拥有资源和独立运行的最小单位。任务调度采用的是时间片轮转抢占式调度方式,而进程作为任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

后来,随着计算机技术的发展,可运行的进程越来越多。进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)的出现,可以满足多个运行单位,而多个进程并行开销过大。因此出现了能独立运行的基本单位——线程(Threads)。

线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。

在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度,从而显著提高系统资源的利用率和吞吐量

2.3 进程与线程的关系:

一个正在运行的软件(如迅雷)就是一个进程,一个进程可以同时运行多个任务( 迅雷软件可以同时下载多个文件,每个下载任务就是一个线程)。他们的关系如下:

引用一个例子:

如果把上课的过程比作进程,把老师比作CPU,那么可以把每个学生比作每个线程,所有学生共享这个教室(也就是所有线程共享进程的资源),上课时学生A向老师提出问题,老师对A进行解答,此时可能会有学生B对老师的解答不懂会提出B的疑问(注意:此时可能老师还没有对A同学的问题解答完毕),此时老师又向学生B解惑,解释完之后又继续回答学生A的问题,同一时刻老师只能向一个学生回答问题(即:当多个线程在运行时,同一个CPU在某一个时刻只能服务于一个线程,可能一个线程分配一点时间,时间到了就轮到其它线程执行了,这样多个线程在来回的切换)

2.4 进程和线程的区别:

所有与该进程有关的资源,都被记录在进程控制块(PCB)中。以表示该进程拥有这些资源或正在使用它们。进程也是抢占处理机的调度单位,它拥有一个完整的虚拟地址空间。当进程发生调度时,不同的进程拥有不同的虚拟地址空间,而同一进程内的不同线程共享同一地址空间。
与进程相对应,线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源。
一个标准的线程由线程ID、当前指令指针PC、寄存器、堆栈线程控制表TCB组成。
而进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成。

2.5 举个例子:

三、多进程与多线程

现代操作系统,比如Mac OSUNIXLinuxWindows等,都是支持“多任务”的操作系统。

也就是操作系统可以同时运行多个任务。比如,你可以一边用浏览器上网,一边听音乐,一边写代码,对于操作系统而言,这就是多任务。

在早期单核CPU时代还没有线程的概念,只有进程。由于CPU执行代码都是顺序执行的。那么,单核CPU是怎么执行多任务的呢?

答案就是时间片轮转调度:简单地说就是把一个处理器划分为若干个短的时间片,每个进程会被操作系统分配一个时间片(即每次被 CPU 选中来执行当前进程所用的时间),每个时间片依次轮流地执行处理各个应用程序,时间一到,无论进程是否运行结束,操作系统都会强制将 CPU 这个资源转到另一个进程去执行,由于一个时间片很短,相对于一个应用程序来说,就好像是处理器在为自己单独服务一样,从而达到多个应用程序在同时进行的效果。

如上图所示,每一个小方格代表一个时间片,大约100ms。假设现在我同时开着 Word、QQ、网易云音乐三个软件,CPU 首先去处理 Word 进程,100ms时间一到,CPU 就会被强制切换到 QQ 进程,处理100ms后又切换到网易云音乐进程上,100ms后又去处理 Word 进程,如此往复不断地切换。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

随着运行的进程越来越多,人们发现进程的创建、撤销与切换存在着较大的时空开销,因此业界急需一种轻型的进程技术来减少开销。于是上世纪80年代出现了一种叫 SMP(Symmetrical Multi-Processing)的对称多处理技术,就是我们所知的线程概念。线程切换的开销要小很多,这是因为每个进程都有属于自己的一个完整虚拟地址空间,而线程隶属于某一个进程,与进程内的其他线程一起共享这片地址空间,基本上就可以利用进程所拥有的资源而无需调用新的资源,故对它的调度所付出的开销就会小很多。

以 QQ 聊天软件为例,上文我们一直都在说不同进程如何流畅的运行,此刻我们只关注一个进程的运行情况。如果没有线程技术的出现,当 QQ 这个进程被 CPU “临幸”时,我是该处理聊天呢还是处理界面刷新呢?如果只处理聊天,那么界面就不会刷新,看起来就是界面卡死了。有了线程技术后,每次 CPU 执行100ms,其中30ms用于处理聊天,40ms用于处理传文件,剩余的30ms用于处理界面刷新,这样就可以使得各个组件可以“并行”的运行了。

自此之后,多线程技术得到广泛应用。

3.1 多进程 vs 多线程

多任务既可以由多进程实现,也可以由单进程内的多线程实现,还可以混合多进程+多线程。混合多进程和多线程的程序涉及到同步、数据共享的问题,这种模型更复杂,实际很少采用。

和多进程相比,多线程的优势在于:

多进程的优点在于:

3.2 多线程的意义:

3.3 并行与并发:

并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行;
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

四、 线程的状态(生命周期)

4.1 新建态(new)

创建一个Thread对象就生成一个新线程。创建完成后就需要为线程分配内存。当线程处于"新线程"状态时,仅仅是一个空线程对象,它还没有分配到系统资源。因此只能启动或终止它。任何其他操作都会引发异常。

例如,一个线程调用了new方法,并在调用start方法之前的就处于新线程状态,可以调用startstop方法。

4.2 就绪态(Runnable)

一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,创建线程运行所必须的系统资源,并调度线程执行run()方法 ,当start()方法返回后,线程就处于就绪状态

处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此,此时可能有多个线程处于就绪状态。

4.3 运行态(Running)

当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。

4.4 阻塞态(Blocked)

所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

将线程挂起(sleep()、wait()、join()、没有获取到锁都会使线程阻塞),可能将资源交给其它线程使用。

suspend()方法被调用。

sleep()方法被调用。

③ 线程使用wait()来等待条件变量。

④ 线程处于I/O请求的等待。

⑤ 线程试图得到一个,而该锁正被其他线程持有。

4.5 死亡态(Dead)

有两个原因会导致线程死亡:

run()方法正常退出而自然死亡;

② 发生异常或者被打断interrupt()导致线程终止。

run()方法返回,或别的线程调用stop()方法,线程进入死亡态。通常Apple使用它的stop()方法来终止它产生的所有线程。

文章参考:
进程与线程的一个简单解释
进程知多少?

上一篇 下一篇

猜你喜欢

热点阅读