操作系统——线程调度

article/2025/9/1 2:07:38

0.关注博主有更多知识

操作系统入门知识合集

目录

6.1线程调度概念

思考题:

6.2典型调度算法

思考题:

6.3Linux线程调度

6.1线程调度概念

在第四章曾经介绍过,线程是操作系统调度的基本单位,那么本篇就不再以进程的视角去看待调度问题了,读者可以把进程理解为只有一个线程的线程。我们曾经介绍过分时操作系统,那么当一个线程的时间片结束之后,操作系统需要选择一个新的线程来占有CPU。那么线程调度的定义就是:在合适的时候以一定的策略选择一个就绪线程投入运行

操作系统需要考虑以下几个点:

  1.调度时机:操作系统必须选择一个合适的时机去调度线程,这个时机可以是线程的时间片结束、可以是被其他线程抢占、亦或是被迫发生中断......

  2.调度策略:操作系统需要选择一个合适的调度策略去调度线程,也可以理解为调度算法。每一种算法都有好有坏,每一种算法都能会对效率产生不同的影响。

  3.调度的指标:线程的调度可不是一句话盖过这么轻松,操作系统必须考虑以下几个指标:

    1)响应速度尽可能快:这就意味着当要发生调度时,调度的过程必须快。特别是针对用户与计算机交互的操作系统,内部一定会频繁地发生线程调度、切换,操作系统必须有能力让处理调度的时间尽可能短,从而使用户在宏观上感觉不到延迟。

    2)线程的处理尽可能快:因为要频繁发生调度,这就意味着线程不能在CPU上待太长时间。也就是说无论是硬件还是操作系统,他们对任务的处理都必须尽可能快。

    3)操作系统吞吐量尽可能大:在单位时间内,调度更多的线程,就意味这这款操作系统的吞吐量更大。

    4)对所有线程要公平:不能让某个线程频繁被调度,也不能让某个线程迟迟不被调度。也就是说要避免调度带来的饥饿问题。

    5)避免饥饿

    6)避免死锁

    ......

    这些调度的指标(原则),他们之间是相互存在矛盾的。例如1)和2),在操作系统当中存在成百上千个任务,所以他们之间要频繁地发生调度,就算调度的过程再快,它依然会影响线程的单位处理时间,也就是说本来在单位时间内可以处理1000条指令,但因为调度把单位时间给消耗了,此时只能执行400条指令了。所以在实际操作系统的设计中,会根据用户的习惯来增强某一侧重点:例如用户注重硬实时任务,那么操作系统的设计更加侧重指标1)。

思考题:

1.你认为Windows和Linux重点侧重哪些调度指标?

Windows和Linux都是面向用户的操作系统,它们必须优先考虑用户的需求,所以非常侧重调度的响应速度;其次,Windows是一款多任务多并发的操作系统,所以Windows也要确保具有较高的吞吐量。

6.2典型调度算法

先来先服务调度(First Come First Serve):

  1.算法:操作系统按照作业创建的先后来挑选作业,先创建的作业优先被操作系统运行

  2.特点:容易实现但效率不高。FCFS算法只考虑了作业的等候时间,而没有考虑运行时间的长短。也就是说一个晚来但是运行时间很短的作业可能要等待很长时间才可能被投入运行。因此FCFS算法不利于短作业。

短作业有限调度算法(Short Job First):

  1.算法:参考运行时间,选取运行时间最短的作业投入运行

  2.特点:容易实现但效率不高。SJF算法忽视了作业的等待时间,一旦有一个来的早但是很大的作业那么将长时间得不到调度,容易造成饥饿。

响应比高者优先调度算法:

  1.响应比定义:作业的响应时间(等待时间+运行时间)与运行时间的比值。响应比=(等待时间+运行时间)/运行时间,可转化成响应比=1+等待时间/运行时间

  2.算法:操作系统会计算每个作业的响应比,选择响应比最高的作业先投入运行

  3.特点:

    1)如果作业的等待时间相同,则运行时间越短的作业,其响应比越高,因此越容易被调度。因而有利于短作业。

    2)如果作业的运行时间相同,则等待时间越长的作业,其响应比越高,因此越容易被调度。因而有利于等候长的作业。

    3)对于运行时间长的作业,其优先级可以随等待时间的增加而提高,当其等待足够久的时候,就能够获得CPU。

优先数调度算法:

  1.算法:根据线程优先数,把CPU分配给优先级最大的线程。优先数=静态优先数+动态优先数。

  2.静态优先数:线程创建时就确定了,在整个运行期间不再改变

  3.动态优先数:动态优先数在线程运行期间可以改变

  4.静态优先数的确定:操作系统会基于线程所需资源的多少、运行时间的长短、类型(IO/CPU型任务、前台/后台线程、内核/用户线程)来确定静态优先数

  5.动态优先数的确定:当线程占用CPU超过一定时常后,其动态优先数就会降低;当进行I/O操作后,就会发生阻塞,此时动态优先数就会升高;当线程等待超过一定时常时,动态优先数也会升高

循环轮转调度法:

  1.概念:把所有就绪线程按先进先出的原则排成队列,新进来的线程添加到队列的末尾。线程以时间片q为单位轮流使用CPU。在CPU上运行一个时间片的线程被操作系统换下,排到队列的末尾,等候下一轮运行。队列与CPU的逻辑关系类似于环形:

  2.优点:保证了公平性,让每个就绪线程都有平等机会获得CPU;保证了交互性,每个线程等待(N-1)*q的时间后就可以重新获得CPU。

  3.时间片的设置:对于时间片q来说,如果q太大就会导致交互差,甚至退化成FCFS算法;如果q太小,线程之间频繁切换,操作系统的开销就会增大

  4.改进:为了让循环轮转的调度算法更加灵活,每个线程的时间片都是可变的,除此之外,还可以组织多个就绪队列,每个就绪队列的管理策略都不同,这与先前讲过的阻塞队列是一个道理。

由此我们可以退回到操作系统的发展,分时系统的出现是计算机的一次"大革命",直到现在,分时系统依然具有优越性。

思考题:

1.静态优先数的三个因素是如何影响静态优先数的?

线程所需的资源越多,其静态优先数就越大,因为它要尽可能先运行完,尽早释放较多资源给后面的线程使用;运行的时间越长,其静态优先数越大,运行时间长的线程先运行完可以避免总是被运行时间短的线程"插队";偏I/O、处于内核态运行的线程,其静态优先数就越大,因为必须及时处理I/O,否则I/O中的数据可能丢失,而在内核态运行线程往往都是比较重要的任务。

2.动态优先数的三个因素是如何影响静态优先数的?

当在CPU上运行超过一定时间后,其动态优先数就会减小,因为要保证线程调度的公平,不能总是让一个线程占用CPU;当发起I/O操作到I/O操作结束时是一段相对较长的时间,其动态优先数应当被增大,因为长时间等待会发生饥饿问题。

6.3Linux线程调度

在这里需要注意一下,Linux实际上并没有线程这个概念,而是叫做轻量级进程。但我们处于用户视角,我们直接把轻量级进程当成线程来看待。读者需要注意,下面的内容有可能会出现线程,也可能会出现进程,但在调度的角度来看,它们都是一样的。

Linux线程类型:

  1.普通线程:采用动态优先级来调度,调度程序(调度模块)周期性地修改优先级(目的是避免饥饿)

  2.实时进程:采用静态优先级来调度,有用户预先指定优先级,在其整个运行生命周期中不会改变

Linux线程的优先级:

  1.静态优先级:线程创建时由用户指定(用户不指定也可以是默认值)

  2.动态优先级:

    1)在线程运行期间可以按照调度策略来动态改变

    2)非实时线程(普通线程)采用动态优先级,其优先级由操作系统的调度模块计算

    3)只要线程占用CPU,优先级就会随着时间流逝而不断减小

    4)task_struct(进程控制块,因为Linux只有轻量级进程,所以可以把它看成线程控制块)中的counter成员表示动态优先级

调度策略:

  1.PCB的policy成员:在Linux的task_struct(PCB)中有一policy成员指明了进程(线程)调度策略(Linux没有线程,只有轻量级进程):

  2.实时进程(线程)的调度策略:

    1)SCHED_FIFO(先进先出):与FCFS调度算法一样,当前实时进程(线程)一直占用CPU直至退出或阻塞或被抢占,再就绪时会被操作系统添加到相同优先级的就绪队列末尾(Linux没有就绪态,但是有就绪队列)。

    2)SCHED_RR(时间片轮转):与其他实时进程(线程)以循环轮转调度法的方式共同使用CPU,确保了同优先级的多个进程(线程)能够共享CPU

  3.普通进程(线程)的调度策略:使用SCHED_OTHER动态优先级的策略来调度普通进程(线程),其task_struct中的counter成员表示进程(线程)的动态优先级

  4.调度策略的改变:系统调用sched_setscheduler()能够让用户改变调度策略,并且实时进程的子孙进程也是实时进程

调度的依据:

  主要依赖task_struct中有关调度策略的属性:

    1)policy:这个成员记录了调度的策略,用来区分实时进程(线程)和普通进程(线程)

    2)priority:所有的进程(线程)的静态优先级

    3)rt_priority:实时进程(线程)特有的优先级,rt_priority=priority+1000

    4)counter:进程(线程)能够连续运行的时间(实际上动态优先级就可以理解为时间计数器,在CPU上的时间越长其值就越小,最后到0便让出CPU)

动态优先级counter:

  1.counter值的含义:进程(线程)能够连续运行的时间,单位时间为时钟滴答tick。假设时钟中断周期tick为10ms,那么当counter=60时,那么该进程(线程)能够连续运行600ms。较高优先级的进程(线程)的counter值一般都比较大。虽然说counter值表示进程(线程)能够连续运行的时间,但在Linux中,把counter看作动态优先级

  2.counter的初值与priority有关:普通进程(线程)创建时counter的处置为priority的值

  3.counter的改变:时钟中断tick时,当前进程(线程)的counter值减1,直到0时放弃CPU

  4.子进程创建时counter:新建子进程的counter从父进程counter中分一半过来。也就是说,假设父进程的counter值为60,则其创建的子进程counter值为30,其本身的counter修改为30。这样做的目的是防止用户无限制地创建子孙进程而长期占用CPU资源

调度时机:

  1.用户态进程(线程)只能通过中断来发生切换(只能被动发生切换):

    1)例如发生时钟中断、I/O中断、系统调用等不可预知的中断,然后CPU陷入内核处理这些中断处理程序,在处理的过程当中调用schedule()接口实现进程(线程)切换

    2)调用schedule()接口时CPU不能处于内核态,因为这样就相当于赋予用户态进程(线程)很高的权限,对操作系统不安全。在CPU处理中断处理程序要调用schedule()接口之前必须先发生一次态的转换,由内核态返回到用户态,在用户态中调用schedule()接口,并且需要根据need_resched标记来检测是否需要需要调用schedule()接口

  2.内核线程可以直接调用schedule()接口实现进程(线程)切换,这是一种内核主动调度的情形

  3.进程(线程)的调度实质就是发生一次进程(线程)切换,切换的过程与中断很像,但是存在一定的差别:发生中断时,操作系统需要保护CPU当前运行进程(线程)的上下文,然后装入中断处理程序的入口地址;而发生进程(线程)切换时,操作系统不仅需要保护CPU当前运行的进程(线程)的上下文,还要恢复被调度而来的进程(线程)的上下文。


http://chatgpt.dhexx.cn/article/fSH4OgUc.shtml

相关文章

【分布式任务调度】(四)XXL-JOB的任务调度执行流程及实现原理

文章目录 1.概述2.调度中心流程2.1.任务配置扫描流程2.2.计算任务触发时机2.2.1.已超时5秒以上2.2.2.超时未超过5秒2.2.3.还未到触发时间 2.3.任务触发流程2.3.1.任务触发线程池2.3.2.参数处理2.3.3.任务触发2.3.4.分片广播策略(补充) 3.执行器流程3.1.任…

分布式任务调度

一、概述 1、定义 业务场景 - 某电商系统需要在每天上午10点,下午3点,晚上8点发放一批优惠券。 - 某银行系统需要在信用卡到期还款日的前三天进行短信提醒。 - 某财务系统需要在每天凌晨0:10结算前一天的财务数据,统计汇总。 - 12306会根据…

【操作系统篇】第五篇——调度(概念,层次,调度时机,切换与过程,方式,评价指标)

​基本概念 ​三个层次 ​高级调度(作业调度) ​中级调度(内存调度) ​低级调度(进程调度) ​三层调度的联系,对比 ​补充知识 ​进程的"挂起态"与七状态模型 ​时机 ​什么时候需要进程调度 ​什么时候不能进行进程调度 ​切换与过程 ​&qu…

操作系统(五)调度

文章目录 一、调度的概念,层次1.1 调度的概念1.2 调度的三个层次1.2.1 高级调度(作业调度)1.2.2 中级调度(内存调度)1.2.3 低级调度(进程调度) 1.3 三层调度的对比1.4 总结 二、进程调度时机&am…

【操作系统】 2.2 调度概念以及调度算法

文章目录 1.调度的概念2.调度的三个层次3.七状态模型4.三层调度的联系和对比5. 进程调度的时机6.进程调度的方式7.进程的切换与过程8.调度算法的评价指标 调度算法先来先服务(FCFS)短作业优先(SJF)最短剩余时间优先(SR…

G1与ZGC

目录 前言JDK7和JDK8的GCG1RegionGC模式Young GCMixed GCFull GC ZGCRegionGC模式 一些感悟一些图文末彩蛋 前言 Java发展至今,最新版本是JDK16,最新的LTS长期支持版本是JDK11,今年9月即将推出JDK17,将是最新一代LTS。 但是&…

Java垃圾收集器之G1

在之前的文章中介绍了JVM的常见垃圾收集器,这边文章我想单独介绍一下G1垃圾收集器。G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。 G1收集器之内存模型…

【JVM】G1垃圾回收器

1.概述 G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一。早在JDK7就已加入JVM的收集器大家庭中,成为HotSpot重点发展的垃圾回收技术。同优秀的CMS垃圾回收器一样,G1也是关注最小时延的垃圾回收器,也同样适合大尺寸堆内存的垃圾收集,官方也推荐使用G1来代…

jvm之G1 GC

写在前面 jdk9以及之后的版本已经将默认的垃圾收集器parallel更换为G1.本文就一起来看下。 1:G1介绍 parallel GC的设计目标是高吞吐量,CMS GC的设计目标是低延迟,而G1的设计目标不是这二者中的任何一个,其设计目标是让GC的STW…

G1 GC详解及设置

一、概述 G1 GC,全称Garbage-First Garbage Collector,在JDK1.7中引入了G1 GC,从JAVA 9开始,G1 GC是默认的GC算法。通过-XX:UseG1GC参数来启用。G1收集器是工作在堆内不同分区上的收集器,分区既可以是年轻代也可以是老…

java 并g1_JVM G1详解

java程序性能 当我们调优java程序时,通常的目标有两个: 响应能力 或者 吞吐量 响应能力 响应能力指一个程序或者系统对请求的是否能够及时响应。 比如: 一个桌面UI能多快的响应一个事件; 一个网站能够多快返回一个页面请求&#x…

垃圾回收之G1收集过程

G1 中提供了 Young GC、Mixed GC 两种垃圾回收模式,这两种垃圾回收模式,都是 Stop The World(STW) 的。 G1 没有 fullGC 概念,需要 fullGC 时,调用 serialOldGC 进行全堆扫描(包括 eden、survivor、o、perm&#xff0…

G1调优分析

目录 1、畅想GC的目标 2、jvm调优的目标 3、GC调优时机 4、垃圾收集器的选择 5、G1调优策略 6、G1垃圾收集实践 6.1、JVM自动选择垃圾收集器 6.2、G1垃圾收集 6.3、GC日志分析 7、小结 前言 c和java之间有一堵由内存动态分配和垃圾收集技术所围成的墙,墙外面的人想进…

JVM垃圾回收器G1详解

1、概述 在我们应用程序所应对的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证应用程序正常进行,而经常造成STW的GC又跟不上实际的需求,我们需要不断地尝试对GC进行优化。G1(Garbage-First)垃圾回收…

G1垃圾回收器

1、最大堆大小 G1管理的最大堆大小为64G。每个Region的大小通过 -XX:G1HeapRegionSize 来设置,大小为 1~32MB ,默认最多可以有2048个Region,G1能管理的最大堆内存是 32MB*204864G 。 使用G1垃圾回收器最小堆内存应为 1MB*20482GB &#xff…

ZGC都出来了,你还不懂G1?

概念 G1(Garbage-First Collector)是一种垃圾回收算法,最早在JDK 6 Update 14中作为实验性功能加入,并在JDK 7 Update 4正式JDK,之后在JDK 9 中成为默认垃圾回收算法,在JDK 10中优化了Full GC性能。 G1是一…

G1详解

一 G1收集器 g1收集器是一个面向服务端的垃圾收集器适用于多核处理器、大内存容量的服务端系统。 它满足短时间gc停顿的同时达到一个较高的吞吐量。 JDK7以上版本适用 “ 先介绍两个概念:吞吐量和响应能力,响应能力和吞吐量是评价一个系统的两个重要指标…

G1垃圾回收器详解

文章目录 前言一、思考问题二、官方文档三、基本介绍四、G1的内存模型五、G1的标记过程六、G1的垃圾回收1、G1过程梳理2、Young GC3、Mixed GC4、Full GC 七、参数介绍八、分析各阶段触发时机根据GC日志分析Young GC的触发时机根据GC日志分析并发标记的触发时机根据GC日志分析M…

G1 GC

G1GC基本概念 G1 GC可以看做是CMS GC的重大升级改造G1 GC的全称是Garbage-First,意为垃圾优先,哪一块的垃圾最多就优先清理他。G1 GC最主要的设计目标是:将STW停顿的时间和分布,变成可预期且可配置的。(默认200ms&…

G1垃圾回收器-----基本知识及原理解析

G1介绍(Garbage first) G1主要面向的是服务端的垃圾回收器。在G1之前,JVM的主要垃圾回收器采用的是物理分代的思想,将内存区域严格的划分成年轻代(young GC)和老年代(major GC)&…