用java编写hrrn算法_硬核操作系统讲解 - sowhat1412的个人空间 - OSCHINA - 中文开源技术交流社区...

本文详细介绍了操作系统中的进程管理,包括进程状态、PCB、进程控制块的作用和信息、进程创建与终止、阻塞与唤醒、进程调度的原则与算法。还探讨了线程的概念、优缺点以及线程的实现方式,最后提到了进程通信的重要性及其主要方式。重点讨论了各种进程调度算法,如FCFS、SJF、HRRN等,以及线程与进程的区别和联系,强调了轻量级进程和协程在高并发场景下的优势。
摘要由CSDN通过智能技术生成

阻塞一般是当系统执行IO操作时,此时进程进入阻塞状态,等待某个事件的返回。

挂起是指进程没有占有物理内存,被写到磁盘上了。这时进程状态是挂起状态。

阻塞挂起:进程被写入硬盘并等待某个事件的出现。

就绪挂起:进程被写入硬盘,进入内存可直接进入就绪状态。

3.2 PCB

为了描述跟控制进程的运行,系统为每个进程定义了一个数据结构——进程控制块 Process Control Block,它是进程实体的一部分,是操作系统中最重要的记录型数据结构。

PCB 的作用是使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程 :

作为独立运行基本单位的标志

实现间断性的运行方式

提供进程管理所需要的信息

提供进程调度所需要的信息

实现与其他进程的同步与通信

3.2.1 PCB 信息

PCB为实现上述功能,内部包含众多信息:

进程标识符:用于唯一地标识一个进程,一个进程通常有两种标识符:

内部进程标识符:标识各个进程,每个进程都有一个并且唯一的标识符,设置内部标识符主要是为了方便系统使用。

外部进程标识符:它由创建者提供,可设置用户标识,以指示拥有该进程的用户。往往是由用户进程在访问该进程时使用。一般为了描述进程的家族关系,还应设置父进程标识及子进程标识。

处理机状态:由各种寄存器组成。包含许多信息都放在寄存器中,方便程序restart。

通用寄存器、指令计数器、程序状态字PSW、用户栈指针等信息。

进程调度信息

进程状态:指明进程的当前状态,作为进程调度和对换时的依据。

进程优先级:用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机

进程调度所需的其它信息:与所采用的进程调度算法有关,如进程已等待CPU的时间总和、进程已执行的时间总和等。

事件:指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。

资源清单

有关内存地址空间或虚拟地址空间的信息,所打开文件的列表和所使用的 I/O 设备信息。

3.2.2 PCB 组织方式

操作系统中有太多 PCB,如何管理是个问题,一般有如下方式。

30dcb8528a63db4e355053f21b1e6451.png

线下数组

线性方式:

将系统所有PCB都组织在一张线性表中,将该表首地址存在内存的一个专用区域

实现简单,开销小,但是每次都需要扫描整张表,适合进程数目不多的系统

b20b3c10f40cb38e21487985c22e700e.png

索引方式

索引方式:

将同一状态的进程组织在一个索引表中,索引表项指向相应的 PCB,不同状态对应不同的索引表。

9f6b3ffca366c3b384daf1d39917eae5.png

链表方式

链接方式:

把同一状态的PCB链接成一个队列,形成就绪队列、阻塞队列、空白队列等。对其中的就绪队列常按进程优先级的高低排列,优先级高排在队前。

因为进程创建、销毁、调度频繁,所以一般采用此模式。

3.3 进程控制

进程控制是进程管理最基本的功能,主要包括创建新进程,终止已完成的进程,将发生异常的进程置于阻塞状态,将进程唤醒等。

3.3.1 进程创建

父进程可创建子进程,父进程终止后子进程也会被终止。子进程可继承父进程所有资源,子进程终止需将自己所继承的资源归还父进程。接下来看下创建的大致流程。

为新进程分配唯一进件标识号,然后创建一个空白PCB,需注意PCB数量是有限的,所以可能会创建失败。

尝试为新进程分配所需资源,如果资源不足进程会进入等待状态。

初始化PCB,有如下几个操作。

标识信息:将系统分配的标识符和父进程标识符填入新PCB

处理机状态信息:使程序计数器指向程序入口地址,使栈指针指向栈顶

处理机控制信息:将进程设为就绪/静止状态,通常设为最低优先级

如果进程调度队列能接纳新进程,就将进程插入到就绪队列,等待被调度运行。

3.3.2 进程终止

进程终止情况一般分为正常结束、异常结束、外界干预三种。

正常结束

异常结束

越界错:访问的存储区越出该进程的区域

保护错:试图访问不允许访问的资源,或以不适当的方式访问(写只读)

非法指令:试图执行不存在的指令(可能是程序错误地转移到数据区,数据当成了指令)

特权指令出错:用户进程试图执行一条只允许OS执行的指令

运行超时:执行时间超过指定的最大值

等待超时:进程等待某件事超过指定的最大值

算数运算错:试图执行被禁止的运算(被0除)

I/O故障

外界干预

操作员或OS干预(死锁)

父进程请求,子进程完成父进程指定的任务时

父进程终止,所有子进程都应该结束

终止过程:

根据被终止进程的标识符,从PCB集合中检索出该PCB,读取进程状态

若处于执行状态则立即终止执行,将CPU资源分配给其他进程。

若进程有子孙进程则将其所有子孙进程终止。

全部资源还给父进程或操作系统。

该进程的PCB从所在队列/链表中移出。

3.3.3 进程阻塞

意思是该进程执行半路被阻塞,必须由某个事件进程唤醒该进程。常见的就是IO读取操作。常见阻塞时机/事件如下:

请求共享资源失败,系统无足够资源分配

等待某种操作完成

新数据尚未到达(相互合作的进程)

等待新任务

阻塞流程:

找到要被阻塞进程标识号对应的 PCB。

将该进程由运行状态转换为阻塞状态。

将该 进程PCB 插入的阻塞队列中去。

3.3.4 进程唤醒

唤醒 原语 wake up,一般和阻塞成对使用。唤醒过程如下:

从阻塞队列找到所需PCB。

PCB从阻塞队列溢出,然后变为就绪状态。

从阻塞队列溢出该PCB然后插入到就绪状态队列等待被分配CPU资源。

3.4 进程调度

进程数一般会大于CPU个数,进程状态切换主要由调度程序进行调度。一般情况下CPU调度时主要分为抢占式调度跟非抢占式调度。

非抢占式:让进程运行直到结束或阻塞的调度方式, 容易实现,适合专用系统。

抢占式:每个进程获得时间片才可以被CPU调度运行, 可防止单一进程长时间独占CPU 系统开销大。

3.4.1 进程调度原则

CPU 利用率

CPU利用率 = 忙碌时间 / 总时间。

调度程序应该尽量让 CPU 始终处于忙碌的状态,这可提高 CPU 的利用率。比如当发生IO读取时候,不要傻傻等待,去执行下别的进程。

系统吞吐量

系统吞吐量 = 总共完成多少个作业 / 总共花费时间。

长作业的进程会占用较长的 CPU 资源导致降低吞吐量,相反短作业的进程会提升系统吞吐量。

周转时间

周转时间 = 作业完成时间 - 作业提交时间。

平均周转时间 = 各作业周转时间和 / 作业数

带权周转时间 = 作业周转时间 / 作业实际运行时间

平均带权周转时间 = 各作业带权周转时间之和 / 作业数

尽可能使周转时间降低。

等待时间

指的是进程在等待队列中等待的时间,一般也需要尽可能短。

响应时间

响应时间 = 系统第一次响应时间 - 用户提交时间,在交互式系统中响应时间是衡量调度算法好坏的主要标准。

3.4.2 调度算法

FCFS 算法

First Come First Severd 先来先服务算法,遵循先来后端原则,每次从就绪队列拿等待时间最久的,运行完毕后再拿下一个。

该模式对长作业有利,适用 CPU 繁忙型作业的系统,不适用 I/O 型作业,因为会导致进程CPU利用率很低。

SJF 算法

Shortest Job First 最短作业优先算法,该算法会优先选择运行所需时间最短的进程执行,可提高吞吐量。

跟FCFS正好相反,对长作业很不利。

SRTN 算法

Shortest Remaining Time Next 最短剩余时间优先算法,可以认为是SJF的抢占式版本,当一个新就绪的进程比当前运行进程具有更短完成时间时,系统抢占当前进程,选择新就绪的进程执行。

有最短的平均周转时间,但不公平,源源不断的短任务到来,可能使长的任务长时间得不到运行。

HRRN 算法

Highest Response Ratio Next 最高响应比优先算法,为了平衡前面俩而生,按照响应优先权从高到低依次执行。属于前面俩的折中权衡。

优先权 = (等待时间 + 要求服务时间) / 要求服务时间

RR 算法

Round Robin 时间片轮转算法,操作系统设定了个时间片Quantum,时间片导致每个进程只有在该时间片内才可以运行,这种方式导致每个进程都会均匀的获得执行权。

时间片一般20ms~50ms,如果太小会导致系统频繁进行上下文切换,太大又可能引起对短的交互请求的响应变差。

HPF 算法

Highest Priority First 最高优先级调度算法,从就绪队列中选择最高优先级的进程先执行。

优先级的设置有初始化固定死的那种,也有在代码运转过程中根据等待时间或性能动态调整 这两种思路。

缺点是可能导致低优先级的一直无法被执行。

MFQ 算法

Multilevel Feedback Queue 多级反馈队列调度算法 ,可以认为是 RR 算法 跟 HPF 算法 的综合体。

系统会同时存在多个就绪队列,每个队列优先级从高到低排列,同时优先级越高获得是时间片越短。

新进程会先加入到最高优先级队列,如果新进程优先级高于当前在执行的进程,会停止当前进程转而去执行新进程。新进程如果在时间片内没执行完毕需下移到次优先级队列。

5f84ed83d0c3bb1fba3f58e63b6b260a.png

多级反馈队列调度算法

3.5 线程

3.5.1 线程定义

早期操作系统是没有线程概念的,线程是后来加进来的。为啥会有线程呢?那是因为以前在多进程阶段,经常会涉及到进程之间如何通讯,如何共享数据的问题。并且进程关联到PCB的生命周期,管理起来开销较大。为了解决这个问题引入了线程。

线程是进程当中的一个执行流程。同一个进程内的多个线程之间可以共享进程的代码段、数据段、打开的文件等资源。同时每个线程又都有一套独立的寄存器和栈来确保线程的控制流是独立的。

进程有个PCB来管理,同理操作系统通过 Thread Control Block线程控制块来实现线程的管控。

3.5.2 线程优缺点

优点

一个进程中可以同时存在1~N个线程,这些线程可以并发的执行。

各个线程之间可以共享地址空间和文件等资源。

缺点

当进程中的一个线程奔溃时,会导致其所属进程的所有线程奔溃。

多线程编程,让人头大的东西。

线程执行开销小,但不利于资源的隔离管理和保护,而进程正相反。

3.5.3 进程跟线程关联

进程:

是系统进行资源分配和调度的一个独立单位.

是程序的一次执行,每个进程都有自己的地址空间、内存、数据栈及其他辅助记录运行轨迹的数据

线程:

是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位

所有的线程运行在同一个进程中,共享相同的运行资源和环境

线程一般是并发执行的,使得实现了多任务的并行和数据共享。

进程线程区别:

一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

资源分配给进程,同一进程的所有线程共享该进程的所有资源。

CPU分配资源给进程,但真正在CPU上运行的是线程。

线程不能够独立执行,必须依存在进程中。

线程快在哪儿?

线程创建的时有些资源不需要自己管理,直接从进程拿即可,线程管理寄存器跟栈的生命周期即可。

同进程内多线程共享数据,所以进程数据传输可以用zero copy技术,不需要经过内核了。

进程使用一个虚拟内存跟页表,然后多线程共用这些虚拟内存,如果同进程内两个线程进行上下文切换比进程提速很多。

3.5.4 线程实现

在前面的内存管理中说到了内核态跟用户态。相对应的线程的创建也分为用户态线程跟内核态线程。

3.5.4.1 用户态线程

在用户空间实现的线程,由用户态的线程库来完成线程的管理。操作系统按进程维度进行调度,当线程在用户态创建时应用程序在用户空间内要实现线程的创建、维护和调度。操作系统对线程的存在一无所知!操作系统只能看到进程看不到线程。所有的线程都是在用户空间实现。在操作系统看来,每一个进程只有一个线程。

ed7fddab59af4c65bf3b260957c731a3.png

用户态线程

好处:

及时操作系统不支持线程模式也可以通过用户层库函数来支持线程模式,TCB 由用户级线程库函数来维护。

使用库函数模式实现线程可以避免用户态到内核态的切换。

坏处:

CPU不知道线程存在,CPU的时间片切换是以进程为维度的,某个线程因为IO等操作导致线程阻塞,操作系统会阻塞整个进程,即使这个进程中其它线程还在工作。

用户态线程没法打断正在运行中的线程,除非线程主动交出CPU使用权。

3.5.4.2 内核态线程

在内核中实现的线程,是由内核管理的线程,线程对应的 TCB 在操作系统里,这样线程的创建、终止和管理都是由操作系统负责。内线程模式下一个用户线程对应一个内核线程。

44b1b8172d7ddf0e0e30765d551d5614.png

内核态线程

注意:Linux中的JVM从1.2版以后是基于pthread实现的,

所以现在Java中线程的本质就是操作系统中的线程。

优点:

一个进程中某个线程阻塞不会影响其他内核线程运行。

用户态模式一个时间片分给多个线程,内核态模式直接分配给线程的时间片增加。

缺点:

内核级线程调度开销较大。调度内核线程的代价可能和调度进程差不多昂贵,代价要比用户级线程大很多。一个线程默认栈=1M,线程多了会导致内存消耗很大。

线程表是存放在操作系统固定的表格空间或者堆栈空间里,所以内核级线程的数量是有限的。

3.4.4.3 轻量级进程

最初的进程定义都包含程序、资源及其执行三部分,其中程序通常指代码,资源在操作系统层面上通常包括内存资源、IO资源、信号处理等部分,而程序的执行通常理解为执行上下文,包括对CPU的占用,后来发展为线程。在线程概念出现以前,为了减小进程切换的开销,操作系统设计者逐渐修正进程的概念,逐渐允许将进程所占有的资源从其主体剥离出来,允许某些进程共享一部分资源,例如文件、信号,数据内存,甚至代码,这就发展出轻量进程的概念。

Light-weight process 轻量级进程是内核支持的用户线程,它是基于内核线程的高级抽象,系统只有先支持内核线程才能有 LWP。一个进程可有1~N个LWP,每个 LWP 是跟内核线程一对一映射的,也就是 LWP 都是由一个内核线程支持。

07c2b7f08ed4624fcabc5e7c812937fe.png

LWP模式

轻量级进程本质还是进程,只是跟普通进程相比LWP跟其他进程共享大部分逻辑地址空间跟系统资源,LWP轻量体现在它只有一个最小的执行上下文和调度程序所需的统计信息。他是进程的执行部分,只带有执行相关的信息。

Linux特性:

Linux中没有真正的线程,因为Linux并没有为线程准备特定的数据结构。在内核看来只有进程而没有线程,在调度时也是当做进程来调度。Linux所谓的线程其实是与其他进程共享资源的进程。但windows中确实有线程。

Linux中没有的线程,线程是由进程来模拟实现的。

所以在Linux中在CPU角度看,进程被称作轻量级进程LWP。

3.5.5 协程

3.5.5.1 协程定义

大多数web服务跟互联网服务本质上大部分都是 IO 密集型服务,IO 密集型服务的瓶颈不在CPU处理速度,而在于尽可能快速的完成高并发、多连接下的数据读写。以前有两种解决方案:

多进程:存在频繁调度切换问题,同时还会存在每个进程资源不共享的问题,需要额外引入进程间通信机制来解决。

多线程:高并发场景的大量 IO 等待会导致多线程被频繁挂起和切换,非常消耗系统资源,同时多线程访问共享资源存在竞争问题。

此时协程出现了,协程 Coroutines 是一种比线程更加轻量级的微线程。类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程。可以简单的把协程理解成子程序调用,每个子程序都可以在一个单独的协程内执行。

863e1f0bedcab45beaf7fad95985be1e.png

协程

协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。

协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多,一般在Python、Go中会涉及到协程的知识,尤其是现在高性能的脚本Go。

3.5.5.2 协程注意事项

协程运行在线程之上,并且协程调用了一个阻塞IO操作,此时操作系统并不知道协程的存在,它只知道线程,因此在协程调用阻塞IO操作时,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度。

因此在协程中不能调用导致线程阻塞的操作,比如打印、读取文件、Socket接口等。协程只有和异步IO结合起来才能发挥最大的威力。并且协程只有在IO密集型的任务中才会发挥作用。

3.6 进程通信

进程的用户地址空间是相互独立的,不可以互相访问,但内核空间是进程都共享的,所以进程之间要通信必须通过内核。进程间通信主要通过管道、消息队列、共享内存、信号量、信号、Socket编程。

3.6.1 管道

管道主要分为匿名管道跟命名管道两种,可以实现数据的单向流动性。使用起来很简单,但是管道这种通信方式效率低,不适合进程间频繁地交换数据。

匿名管道:

日常Linux系统中的|就是匿名管道。指令的前一个输入是后一个指令的输出。

命名管道:

一般通过mkfifo SoWhatPipe创建管道。通过echo "sw" > SoWhatPipe跟cat < SoWhatPipe 实现输入跟输出。

匿名管道的实现依赖int pipe(int fd[2])函数,其中fd[0]是读取断描述符,fd[1]是管道写入端描述符。它的本质就是在内核中创建个属于内存的缓存,从一端输入无格式数据一端输出无格式数据,需注意管道传输大小是有限的。

7dab1c5e95abea074f3ad21fa084c2e1.png

管道通信底层

匿名管道的通信范围是存在父子关系的进程。由于管道没有实体,也就是没有管道文件,不会涉及到文件系统。只能通过

fork子进程来复制父进程 fd 文件描述符,父子进程通过共用特殊的管道文件实现跨进程通信,并且因为管道只能一端写入,另一端读出,所以通常父子进程遵从如下要求:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值