操作系统基础知识点整理

概述

用户态和内核态

概念

参考:用户态和内核态的理解和区别

当进程执行用户自己的代码时处于用户态,此时特权级最低,为3级。当一个进程因为系统调用陷入内核代码中执行时,处于内核态,此时特权级最高,为0级。特权级低的状态不能访问特权级高状态的地址空间,这样用户态的程序不能随意操作内核地址空间,一个进程不会修改另一个进程地址空间中的数据。

进程切换需要从用户态切换到内核态,在切换到用户态。

用户态和内核态的切换

  1. 系统调用

    用户进程通过系统调用申请使用操作系统提供的服务程序完成工作。

  2. 异常

    CPU在执行在用户态下的程序,发生了一些没法预知的异常,这时会触发当前运行进程切换到处理此异常的内核相关进程中。如缺页异常。

  3. 中断

    当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令而转到与中断信号对应的处理程序去执行。

进程管理

进程与线程

进程

一个进程实体由程序段、数据段和PCB(程序控制块)三部分构成,其中PCB是标志一个进程存在的唯一标识,程序段是进程运行的程序的代码,数据段则存储程序运行中相关的数据。

线程

引入线程的目的是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。有了线程,线程切换时,有可能会发生进程切换,也有可能不发生进程切换,平均而言每次切换所需的开销就变小了,因此能够让更多的线程参与并发,而不会影响到响应时间等问题。

区别

引入进程的目的是为了更好的使多道程序并发执行,提高资源的利用率和系统吞吐量;引入线程的目的是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

  1. 调度

    线程是系统调度的基本单位,在同一进程中,线程的切换不会引起进程的切换。在不同进程中进行线程切换,如从一个进程内的线程切换到另一个进程的线程中,会引起进程切换。

  2. 拥有资源

    进程是系统分配资源的基本单位,而线程不拥有系统资源,但是线程可以访问所隶属进程的系统资源。

  3. 系统开销

    创建或者销毁进程时,系统都要为之分配或者回收资源,如内存空间、I/O设备等,因此操作系统所付出的开销远大于创建或者撤销线程的开销。

    进程切换时候,需要执行CPU环境的保存和系统资源的切换,而线程切换只需要保存和设置少量寄存器内容,开销小。

  4. 通信方面

    进程间通信需要进程同步和互斥手段的辅助,以保证数据的一致性。而线程间可以直接读写进程数据段来进行通信。

进程同步

临界区

对临界资源进行访问的那段代码称为临界区。

为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。

同步与互斥

同步:多个进程按一定顺序执行

互斥:多个进程在同一时刻只有一个进程能进入临界区

信号量

信号量创建时会有一个初始值,信号量大于0,表示

进程通信

管道

管道分为匿名管道和命名管道,其本质是一个文件,有一个读端和写端。半双工的通信方式,数据只能单向流动,提供面向字节流的服务,生命周期随进程。

管道读写的特点:当管道中没有数据的时候,对管道的读会阻塞,知道管道中有数据为止;当管道中中数据满的时候,对管道的写也会阻塞。

  • 匿名管道

    匿名管道是在内核中开辟一个缓存区。

    匿名管道只能在有血缘关系的进程使用,比如父子进程,父进程在产生子进程之前必须打开一个管道文件,然后fork产生一个子进程,这样子进程就通过拷贝父进程的进程地址空间获得同一个管道文件的描述符,达到同一个管道通信的目的。除了父子进程没人知道这个管道文件的描述符,所以这个管道中的信息无法传递给其他进程。保证了传输数据的安全,但是也降低了管道的通用性。

  • 命名管道

    命名管道会有一个全局可见的文件名以供别人打开使用,是一个设备文件。即使进程和创建管道的进程没有血缘关系,只要可以访问该路径,就可以通过命名管道通信。

消息队列

消息队列是由消息组成的链表,存放在内核中由消息队列标识符标志。和管道相比,它具有更大的灵活性,他提供有格式的字节流,和具有类型的消息。同样他可以在几个进程间复用,不管这几个进程是否有亲缘关系,这一点和命名管道相似。另外他是随内核而持续的,与有名管道随进程持续相比,生命力更强大。

信号量

信号量是一个计数器,用来控制多个进程对资源的访问。

信号量在创建时会有一个初始值,表示同时有几个任务可以访问该资源。当信号量为正时,表示可以资源可以访问,同时信号量减一,访问完毕后,就释放信号量,同时将信号量加一。如果当前信号量为负数,表示无法获得信号量,需要等待该信号量可用。

共享内存

共享内存允许两个或者多个进程访问同一块内存,当一个进程改变了内存中内容的时候,其他进程都能察觉到这个数据的变化。

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要系统调用或者切入内核的过程。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。

套接字

可用于不同机器间的通信。

进程调度算法

  • 先来先服务

    按照进程进入就绪队列的先后次序来选择进程

  • 短进程优先

    从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给他

  • 高响应比优先调度算法

    按照高响应比((已等待时间+要求运行时间)/要求运行时间)优先的原则,每次计算就绪队列中每个进程的响应比,然后选择最大的进程投入运行。

  • 时间片轮转调度算法

    当某个进程执行的时间片用完,调度程序便停止该进程的执行,并将它送就绪队列的末尾。等待下一时间片再执行。然后把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程,在一给定的时间内,均能获得一时间片处理机的执行时间。

  • 优先权调度算法

    按照进程的优先权大小来调度。

  • 多级队列调度算法

    根据进程的性质和类型的不同,将就绪队列再分为若干子队列,所有的进程按其性质排入相应的队列中,而不同的就绪队列采用不同的调度算法。

进程状态

  • 就绪态:

    除了处理机时间片,其他资源准备就绪,等待处理机时间片的分配就可以进入运行态

  • 运行态:

    正在处理机上运行

  • 阻塞态:

    进程在等待某一事件而暂停运行。

  • 创建态

  • 结束态

同步和互斥的区别。同步、异步、阻塞、非阻塞的区别

同步和互斥的区别

同步体现的是一种协作性,互斥体现的是一种排他性

同步:并发的线程互相等待和互通信息

互斥:某一资源同时只允许一个访问者对其进行访问,具有唯一性和排他性

同步和异步的区别

关注的是消息通信机制

同步:调用者会主动等待调用的返回结果

异步:调用者不会主动等待调用结果,而是在调用发生后,被调用者通过某种方式来通知调用者

阻塞和非阻塞的区别

关注的是程序在等待调用结果时的状态

阻塞:调用结果返回前,当前线程会被挂起,即阻塞

非阻塞:指调用结果没返回,也不会阻塞当前线程

死锁

什么是死锁

由于系统中存在一些不可剥夺的资源,而当两个或两个以上的进程占有自身资源,并请求对方资源时,会导致每个进程无法向前推进。

死锁产生的原因

  • 系统资源的竞争

    系统中拥有的不可剥夺资源,其数量不足满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局,如打印机等。

  • 进程推进顺序非法

    进程在运行过程中,请求和释放资源的顺序不当。比如进程P1、P2分别保持了自身资源,而进程P1申请资源R2、进程P2申请资源R1,两者都会因为申请资源被占用而阻塞。

必要条件

  1. 互斥性

    进程要求分配的资源具有互斥性,一次最多只能被一个进程使用。

  2. 不可剥夺性

    进程在未使用完之前,资源不能被强制夺走。

  3. 请求与保持

    进程在占有自身资源的同时并请求新的资源。

  4. 循环等待

    进程资源的循环等待。

解决方案

死锁预防

事先预防,实现起来比较简单,但是条件严格,效率不高。设置某些限制条件,破坏死锁的4个必要条件中的一个。

  • 破坏互斥条件:系统中所有资源不能同时访问,不太现实。
  • 破坏不可剥夺条件,允许剥夺其他进程已经占有的资源,可能会造成前段工作的失效。如果频繁发送会增加系统开销。
  • 破坏请求与保持条件:采用预先资源分配法,一次性分配进程需要的所有资源,缺点是会严重浪费系统资源。
  • 破坏循环与等待条件,采用顺序资源分配,缺点是会造成编程不便

死锁避免

同样是事先预防,不同的是动态的根据情况来避免死锁,性能会比较好

  • 系统安全状态

    不安全的系统可能会导致死锁,安全的系统状态不会导致死锁,如果系统分配不会进入不安全的系统状态就给进程分配资源。

  • 银行家算法

    把操作系统视为银行家,操作系统管理的资源视为资金,进程向操作系统申请资源相当于贷款。采用预先资源分配策略,主要的数据结构是可利用的资源向量。

死锁检测与恢复

  1. 资源剥夺法

    挂起某些死锁进程并剥夺其资源

  2. 撤销进程法

    撤销一个甚至全部死锁并剥夺其资源

  3. 进程回退法

    让一个或多个进程回到不至于造成死锁的状态

内存管理

创建进程首先要将数据和程序装入内存,程序装入内存步骤分为编译、链接和装入内存。

逻辑地址和物理地址

逻辑地址:是从应用程序角度看到的内存地址,又叫相对地址。程序编译或者链接装配后指令和数据所用的相对地址的空间。不同进程可能有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。

物理地址:是地址转换的最终地址,进程在运行时执行指令和访问数据都要通过物理地址从内存中存取,是内存单元真正的地址。

内存管理方式

  • 连续分配
  • 非连续分配
    • 基本分页:内存分为固定的块,按物理结构分,会有内部碎片
    • 基本分段:内存块的大小不固定,按逻辑结构分,会有外部碎片
    • 分页和分段结合:基本分段和基本分页的结合,会有内部碎片

虚拟内存

概念

物理上扩展内存相对有限的条件下,从而在逻辑上扩充内存的方式。

通过外存上的空间来扩充内存空间,将程序一部分装入内存,一部分留在外存。当程序执行过程中,当访问的信息不在内存时,由操作系统将所需要的的部分调入内存;另一方面,也可以通过页面置换算法把内存中暂时不用的内容换出到外存。通过这样的换入换出,使得系统在逻辑上能够使用远比物理内存大的内存容量。

虚拟内存的空间大小

  • 小于或等于内存加外存之和
  • 小于或等于计算机地址位数能容纳的最大容量。假设地址是32位的,按照字节编址,一个地址代表1B存储空间,则虚存的大小要小于4GB(2的32次方B)

页面置换算法

  1. 最佳置换算法

    选择那些永不使用,或者在最长时间内不再被访问的页面置换出去

    实现起来比较困难,且开销大

  2. 先进先出置换算法

    总是淘汰最先进入内存的页面

    实现简单,但是性能差

  3. 最近最久未使用置换算法

    选择最近最久未使用的页面予以淘汰

  4. 时钟算法:选择最近未用的页面

面试题

协程

是一种比线程更轻量级的实现,一个线程可以有多个协程,协程不是被操作系统内核所偶管理,而是完全由程序控制(也就是在用户态执行)。

优点在于开销小,协程切换不需要内核态和用户态的切换。

python的yield/send方式可以实现协程,和线程的阻塞有本质的区别。

多进程和多线程模型的选择

多进程模型:

优点:内存隔离,单个进程的异常不会导致整个应用的崩溃;方便测试,编程简单。

缺点:创建和销毁、切换的开销大

使用场景:对内存隔离要求较高的场景

举例:chrome浏览器也是多进程方式。 (原因:①可能存在一些网页不符合编程规范,容易崩溃,采用多进程一个网页崩溃不会影响其他网页;而采用多线程会。②网页之间互相隔离,保证安全,不必担心某个网页中的恶意代码会取得存放在其他网页中的敏感信息。)

多线程模型:

优点:线程的通信方便,可以共享进程的数据;创建和销毁的开销小

缺点:一个线程的崩溃会引起整个进程的崩溃;线程执行的随机性可能会导致逻辑混乱,甚至发生死锁现象。

使用场景:存在大量IO或者计算操作,或者需要和用户交互时,使用多线程有利于提高系统的并行性和用户界面的快速响应。

猜你喜欢

转载自blog.csdn.net/weixin_41524366/article/details/107486734