本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
在上文《Java并发编程:硬件上的并发中篇》,我们了解了进程和线程的概念和区别,以及父子进程的概念。接下来,本文将为大家讲解操作系统调度的过程。
什么是调度?
在操作系统中,只要同时存在两个及以上的进程,就需要由操作系统来决定由哪个进程先执行、执行多久,而这个过程就是调度。
什么时候会发生调度?
在操作系统中,一个进程在处理机中运行结束,要退出处理机,或者是由于其它原因,导致当前进程被迫放弃处理机,就会发生调度。
调度的过程
- 保存当前现场。将当前正在执行的进程在处理机中的数据(例如程序计数器和寄存器中的数据)提取出来,保存到进程PCB的指定位置
- 根据调度算法选取下一个要执行的进程。根据调度算法,从就绪状态的进程队列中,选取一个进程,将之改为执行状态
- 将选中的进程交给处理机,并将PCB中的相关数据写入到处理机中(程序计数器、寄存器等),恢复处理机现场
上述PCB数据与处理机数据的切换,也就是我们日常所说的上下文切换。
线程的引入
在最开始的时候,进程既是操作系统资源分配的基本单元,也是操作系统调度的基本单位,但是操作系统调度过程中,处理机数据的切换是非常频繁的,切换数据的大小,直接影响到了操作系统调度的效率。因此,操作系统引入了线程。
线程的特点
- 轻实体。线程除了一些基本的、必不可少的资源,基本不拥有系统资源。
- 独立调度和分派的基本单位。在操作系统中,线程是独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程占用资源较少,因此处理机切换代价较小。
- 可并发执行。在多核CPU中,同一进程中的不同线程可以并发执行,不同进程中的线程也可以并发执行
- 共享进程资源。同一进程中的线程,共享进程资源。
- 处理机进行线程切换时,如果是同一进程中的,不需要进行进程切换;但是如果切换的线程是属于另外一个进程的,就需要进行进程切换。
调度方式
- 非抢占式调度
当一个线程在处理机中运行时,除非其主动放弃处理机,否则必须等这个线程执行完成以后,才能调度下一个线程进入处理机执行。
此调度方式的弊端在于如果有紧急任务,也必须等待当前处理机中的线程执行完成才有机会执行。这种情况下,就有可能出现我们要打开一个文档的时候,由于没等到处理机而一直等待,无法打开。 - 抢占式调度
操作系统可以根据一定的规则,比如优先级原则、短作业原则、时间片原则等,将正在执行的线程暂停,切换另一个线程进入处理机中执行。
调度策略
在抢占式调度中,操作系统会按照一个的算法规则去选择需要执行的线程,接下来我们来看下操作系统调度中常见的算法规则。
-
优先级原则
操作系统将按照每个线程创建时设定的优先级去调度,优先级高的优先执行,优先级低的后面执行。若新创建的线程优先级高于处理机中的线程,则会停止处理机中的线程,然后先执行新创建的线程。
这种算法的好处是紧急任务可以得到及时处理,但是弊端也非常明显,就是优先级低的线程,在极端情况下,可能永远都得不到执行。
-
短作业原则
操作系统将按照每个线程的服务时间来进行线程调度,服务时间短的优先执行。若新创建的线程服务时间短于处理机中的线程,则会停止处理机中的线程,然后先执行新创建的线程。
这种算法的好处是可以加快线程的处理速度,快速处理掉尽可能多的线程。但是这种算法对紧急任务较为不友好,紧急任务也有可能因为服务时间长而被排到后面执行。
-
时间片原则
操作系统将处理机的执行时间分为一个个的时间片,然后让各个线程按照时间片交互执行。比如线程A先执行了10毫秒,然后切换到线程B再执行10毫秒,一直按照时间片切换执行,直到线程执行结束。
Linux的调度策略
Linux的调度算法综合了优先级原则和时间片原则,这种策略的名字叫做CFS。
当一个新的线程被创建时,Linux会根据这个线程的优先级分配它的时间片比例。分配到时间片以后,Linux并不是死板的按照固定轮流执行的方式去执行的,而是可以动态执行的。比如有两个线程,各自分配了10秒的时间片,Linux并不是让两个线程轮流交互执行,而是可以让线程A优先执行了7秒,则接下来操作系统会调高线程B的优先级,让它也执行到两个线程时间片比例一样以后(即线程B也执行完7秒),再调回其优先级。
后言
既然看到这里了,感觉有所收获的朋友,不妨来个大大的点赞吧~~~