【操作系统】进程和线程

进程是操作系统中最核心的概念,因为它代表了操作系统最根本的价值,即多个程序的并发,以及人机交互处理,像其它的文件管理、io管理、存储器管理等,都是在处理机管理基础上发展而来的。

一、进程基本概念

操作系统的主要作用就是为了实现并发,但是如果对并发的程序没有任何监督和管理,并发容易造成间断程序、程序失去封闭性、不可再现性(即程序异步流程出错)。所以引入进程来保证正确性。

操作系统单独创建了进程这样一种资源,就像内存、IO设备、文件资源一样。进程可以看做是一种资源,但是从本质上看,进程就是一个独立运行的程序,和外界无关。

在为一个程序开辟一个进程的时候,操作系统自动为其创建一个进程控制块PCB,对该程序进行控制,PCB就是一块内存,其中包含了进程标识符、处理机状态、进程调度信息、进程控制信息等内容,这些东西,程序本身不需要知道,只是操作系统用来管理需要知道的。进程有正在执行、终止释放、创建、就绪、阻塞等状态。其中进程还可以被挂起,这也是一种阻塞状态,因为程序不向下运行,不运行是因为用户阻止。这样的一串进程状态体现了进程的一个从产生到消失的全过程。操作系统根据进程的状态来对其进行管理,具体来说,计算机在组织PCB数据结构的时候,主要采用了有链表存储、索引存储等方式。

进程也有父进程和子进程的概念,类似于面向对象中的继承关系。父进程可以调度子进程中的资源。这体现了进程之间的通信实际上,因为父进程在创建子进程的时候,一定是向其传递了信息的。

二、进程同步

进程的同步是指进程之间受限于某种制约关系,必须相互等待的问题,本质上就是为了保证多个程序并行运行的正确性和复现性。这种受限的制约关系一般都是因为资源的争夺和冲突,这种资源叫做临界资源。而进程中的程序中,访问临界资源的那段代码叫做临界区。如果进程中的代码执行到临界区就被卡住了,那么就要释放处理机资源,以免进入忙等。

1、硬件同步机制

但是现在的计算机几乎都不使用软件实现进程同步,而改用硬件实现,即关中断,TS指令,Swap指令

2、信号量机制

除了硬件同步,还有信号量机制实现单机进程同步,信号量包括整形信号量(等待wait和激活signal两条原语),记录型信号量(资源并非1个,而是多个的时候使用),AND型信号量(即一次性全部把资源交给进程,这样可以避免死锁等错误),信号量集(一次申请多个临界资源,避免死锁)。

3、管程

信号量的优点是简单易懂,原语都是wait和signal,缺点是太分散,系统管理麻烦。管程就是将具体的进程同步原语抽象化,并组织在一起,对管程中的数据结构的操作就相当于对进程的操作,这样,大量的分散的进程操作就集中在了数据结构中,管理起来非常方便。

三、进程通信

进程的通信需要满足两个需求,一是能够传送大量的数据,二是方便好用。
进程通信的类型:

1、共享存储器系统

操作系统在内存中开辟出来一个共享数据区,或者构建一个共享数据结构,让所有的指定的进程都可以访问这一公共内存区域,实现进程通信。

2、管道通信系统

管道两端连接了一个读进程和写进程,实现数据在进程两端的传递。

3、消息传递机制

操作系统有一组通信命令,它操作的对象是消息,如果进程需要通信,就产生一条包含数据的消息,告知操作系统,由操作系统代办完成进程的通信。
操作系统来处理消息,需要采用一些机制,因此,消息通信的实现方式:
1、直接通信原语,系统提供的通信原语命令是send和receive。
2、信箱通信,即定义一组信箱数据结构,且将信息分成私用邮箱、公用和共享等类别。也就实现了消息发送的多样化。

4、客户机-服务器系统

1、套接字:即通过ip地址和端口实现电脑上的进程之间的通信,很多数据库都提供该种方式,http网络服务器,网络邮箱服务器,几乎所有应用层服务器都提供该种方式。
2、远程过程调用:即利用存根stub,实现本地进程调用远程服务器上的进程中的过程,且对程序员完全透明。这是一种本地化操作,把远程的当做本地的。
3、远程方法调用:如果是面向对象的,那调用的就是方法。

四、线程

由于进程的状态改变、创建、销毁、挂起保存上下文等操作的代价相当大,所以将进程拥有资源的操作和进程控制调度和分派的操作分离出来。仍然保持进程 是拥有资源的最小单位,但是 线程 是操作和调度的最小单位。这样提高了计算机运行效率,从繁重的计算机进程中解放出来。

但是,线程依然具有自己的TCB块,但是存储的信息非常少,只是标识了该线程的存在状态。

线程有两种实现方式:

1、内核支持线程

从前面进程的管理可知,进程是运行在用户态的,当进程需要进行状态转换的时候,就需要切换到内核态,调用系统内核中的代码来操作进程。同样地,线程也可以采用内核来支持,就像支持进程那样,在这种模式下,内核空间为每一个内核线程设置了一个线程控制块,可以允许多个线程并行执行。如果一个线程阻塞了,那么该线程所属的进程会调用其他线程,继续执行,不会造成程序终止。但内核支持的缺点就是切换模式状态的代价比较大。

2、用户级线程

也就是说,内核的眼中只有进程,完全不关心进程内部的线程如何操作,只关心进程的切换。因此,进程内部线程的调度和切换就非常灵活,算法也是多种多样,且切换模式的代价小了很多,因为不需要调用内核的代码和寄存器等等,所以用户级线程和平台无关。但是其缺点是在线程执行一个系统调用的时候,线程阻塞,进程也被阻塞,且内核每次分配给进程一个处理机,难于实现并行处理。

3、组合方式

也就是将内核和用户态都实现对线程的支持,分别为映射。但是策略有多对1,多对多等等。比如window就是多对多,当然了,这种方式也有局限性,给内核的压力很大。

五、进程和线程的调度

作业是指即将进入程序处理机进行处理的一个事项,一般可以等同于程序来理解,即多道批处理程序中的一道,作业很可能涉及多个进程,协同处理完成一个任务。对于作业的调度即高级调度,对于进程的调度称为低级调度短程调度(因为其运行时间短,且非常频繁),而内存调度称为中程调度,即存储器管理里的对换Swapping,指的是内存满负荷运行时需要采用的一种机制。

整个调度算法的目标就是提高处理机的利用率,且实现平均的周转时间最短系统的作业吞吐量大,对实时响应能够及时有效

1、作业调度

整个过程是把用户提交的作业用IO设备放在磁盘上,进而放在一个后备作业队列里(后备队列仍然没有进入内存,所谓内存就是在内存上的数据和指令就是要等待被执行的,而不是闲置的),再从外存调入内存,进行处理。

作业调度会设置作业控制块来进行控制JCB,由于作业是一个比较复杂的过程,所以在调入内存的时候,相应地会提供一个作业说明书,用来指导系统如何对作业进行控制。

调度算法主要有FCFS先来先服务算法短作业优先算法SJF(作业说明书中给出了时间),优先级调度算法PSA(即针对实时系统而言),高响应比优先调度算法(HRRN,综合了前面的算法,既考虑了短作业的等待时间,又照顾到长作业的响应效率)。

2、进程调度

进程调度就是有的进程要先执行,有的要后执行,需要调换顺序,因此进程调度和作业调度息息相关,毕竟一个作业也是由多个进程和线程构成。

整个过程包括保存处理机的当前信息,即上下文信息;按照某种算法选择要调入的信息;把处理机分配给进程。因此,为了实现进程的调度,需要排队器、分派器、上下文切换器。一次进程的切换调度,需要涉及到上千条指令,任务繁重。

调度的方式也有两种,抢占方式和非抢占方式,即内核在接收到调度命令之后,是不是要直接阻断当前运行的程序,转而执行即将要调度的进程。抢占的行为需要遵循一定的原则,即优先权原则,短进程优先原则,时间片原则。
非抢占方式也就不涉及中断了,只有在进程自身陷入时才中断切换。
抢占方式是实现分时系统实时响应的必须策略,这个就是外部强迫其中断切换。

调度算法主要采用轮转法,即时间片方法,达到并发效果。进程切换有时间片使用完,或者进程已经运行完毕,不再需要时间片两种情况。在轮转法中,时间片长短的确定非常重要,它直接影响着调度的处理性能。

优先级调度算法:静态优先级或者动态优先级两种,这和抢占与非抢占方式也有直接的关系。

多队列反馈调度算法MFQ:核心就是设置多个调度队列,短队列的优先级比较高,等待时间长的队列优先级别高。这种算法考虑了进程的长短,也考虑了长进程的处理机会,具有一定的公平性,但还不是绝对的公平。

基于公平原则的调度算法:该种算法能够保证调度程序选择最满足公平原则的一个进程分派给处理机。

实时调度:即要调度达到满足HRT任务和SRT任务。为了满足这两类任务的需求,必须提供任务的开始时间和截止时间,同时要求处理机的处理能力强,而且采用抢占式调度机制,快速切换机制。
最早截止时间优先算法EDF:即完全按照截止时间来对任务排序,也包括抢占和非抢占两种方式。

最低松弛度优先LLF算法:即计算任务的紧急程度,然后最紧急的任务优先执行。

在常用的算法中容易出现优先级倒置的问题,此时可以采用动态优先级策略来解决该问题。

六、进程死锁

引起死锁的原因很多,就像数据库管理系统里也很容易引起死锁一样,操作系统里造成进程死锁的主要原因是竞争不可抢占性资源引起死锁,竞争消耗性资源引起死锁,进程的推进顺序不当造成死锁等等。

死锁有四个必要条件

如果有一个不满足,就不会产生死锁,避免死锁的策略也从此而来:

1、互斥条件:在某一段时间,进程所占有的资源不可以给其它进程使用。公共内存区除外。
2、请求和保持条件:在进程进行到一半,又对资源提出新的请求,此时却不放弃已经保持的资源。
3、不可抢占条件:进程已有的资源在进程结束之前不可被抢占,只能由其自行释放。
4、循环等待条件:类似哲学家进餐问题,大家都在等待,造成循环等待。

避免死锁的方法

预防死锁:总体来讲是破坏死锁必要条件中的其中一个。总结一下就是:进程每次都申请所需的全部资源,不再分步申请(难度较大);主动释放已占用的资源,让其它进程来抢占;有序分配资源,避免陷入循环等待

避免死锁:在这里引入了将系统保持在安全状态的概念。将系统始终保持在安全状态,指的是每时每刻,系统所拥有的资源总和可以完成当前所有作业、任务、进程,满足他们的要求。银行家算法DIJKSTRA算法可以避免死锁发生,这个算法可能和路由协议算法发生混淆。

死锁的检测和摘除资源分配图RAG是一个有向图,死锁在资源分配图中的表现就是环。死锁定理(在数据库中也提到了)就是一步步解除资源分配图中的结点和连线,如果剩余的仅仅是孤立的点,说明不会产生死锁,如果剩余的是一个环,那么说明当前存在死锁,需要解除死锁。
解除死锁的方法包括:终止所有的进程;逐个终止进程,这样可以避免代价太大。此时提出代价最小化策略。

猜你喜欢

转载自blog.csdn.net/dongrixinyu/article/details/78877448