操作系统复习(二)进程管理

进程

1. 进程与线程的区别

进程:指的是系统中正在运行的一个应用程序,程序一旦运行就是进程;进程是系统资源分配的最小单位。

线程:线程是系统分配处理器时间资源的基本单元,或者说进程内部独立执行的一个单元执行流;线程是程序执行的最小单位。
在这里插入图片描述
从上图中可以看出:一个进程中可以有多个线程,多个线程共享进程的堆和方法区(JDK1.8后的元空间)资源,但是每个线程有自己的:程序计数器,虚拟机栈,本地方法栈。

总结:线程是进程划分成的更小的运行单位,一个进程在执行的过程中可以产生多个线程。线程与进程最大的区别在于:进程是相互独立的,但是线程则不一定,同一进程中的不同线程极有可能相互影响。线程执行开销小,但不利于资源的管理和保护;进程则相反。线程上下文切换比进程上下文切换快得多。

2. 进程有哪几种状态?

新建:进程正在被创建时,他的状态是”创建态“,在这个阶段系统会为进程分配资源,初始化PCB

操作系统为每一个进程都提供了一个PCB:程序控制块,它记录着与此进程相关的信息:进程状态、优先级、PID等等。

每个进程都有自己的PCB,所有的PCB都放在一张表格中维护,这就是进程表。调度器根据这个表来选择处理器上运行的进程。
在这里插入图片描述
就绪:当进程创建完成后,便进入了”就绪态“,处于就绪态的进程已经具备了运行条件,但由于没有空闲CPU,就暂时不能运行。

运行:如果一个进程在CPU上运行,那么这个进程处于”运行态“,就暂时不能运行。

阻塞:在进程的运行过程中,可能会请求等待某个事件的发生(如:等待某种系统资源的分配、或者等待其他进程的响应),在这个事件发生以前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让它进入”阻塞态“,当CPU空闲时,又会选择另一个进入就绪态的进程在CPU上运行。

终止:一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入”终止态“,操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。当终止进程的工作完成后,这个进程就彻底消失了。

3.进程的上下文切换

对于CPU来说,它只知道读取指令,执行指令,执行下一条指令。CPU并不关心当前执行的指令来自于哪个进程或线程,这是由操作系统来管理的。由于程序中总是有磁盘读写、网络交互等动作,这些动作比CPU的速度慢了很多个数量级,**为了不让CPU盲目等待这些操作,使多个程序近乎于同时运行,a程序在执行IO读写时把CPU交给b程序,b程序发送网络包时再把CPU交给c程序,尽可能地提高CPU的利用率。**要让这些进程都有机会被CPU执行,操作系统就得在一个进程被CPU执行时,将其切换走,把CPU让给其他进程,这就是进程的上下文切换。

4. 进程是如何进行切换的?

CPU的作用就是读取指令、执行指令、执行下一条指令。操作系统需要给CPU提供从哪里读取指令、执行需要的数据。如果在执行过程中被切换走,还需要提供CPU计算过程中产生的临时数据。操作系统通过给CPU的各种寄存器赋值来完成这些操作,包括程序计数器中下一条指令的地址,数据寄存器中程序数据段的起止地址,代码寄存器里程序指令段的起止地址,各种通用寄存器中的数据等。

切换过程就是切换CPU中各种寄存器的值,让CPU获取执行的指令和数据,这些在进程运行过程中存在寄存器中的值与程序计数器就是上下文。

5. 为什么虚拟地址切换慢?(为什么进程切换慢)

由于每个进程都有自己的虚拟地址空间,显然每个进程也有自己的页表。那么当进程切换后页表也要进行切换,页表切换后快表就失效了,那么虚拟地址转换为物理地址就会变慢,表现出来就是程序运行变慢了。而线程切换则不会导致TLB(页表缓冲区)失效,因为线程切换无需切换地址空间,因此我们通常说进程切换比线程切换慢就是这个原因。

进程还有一点:特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。

6. 进程调度的方式

可抢占式:就绪队列中一旦有某进程优先级高于当前正在执行进程的优先级,操作系统便立即进程调度,完成进程间切换。

不可抢占式:即使在就绪队列中存在有某个进程优先级高于当前正在执行的进程的优先级,当前进程仍占用处理器执行,直到该进程自己进入阻塞状态,或时间片用完或执行完系统调用准备返回用户进程前的时刻,才发生调度,让出处理器。

7. 进程调度的策/算法

先到先服务调度(FCFS)算法:从就绪队列中选择一个最先进入该队列的进程分配资源,使它一直执行到结束或发生事件而被阻塞放弃占用CPU后再进行调度。

短作业优先(SJF)的调度算法:从就绪队列中选择一个预估运行时间最短的进程为之分配资源,使它立即执行并一直执行直到完成或发生某事件而被阻塞放弃占用CPU后再进行调度。

**时间片轮转调度算法:**时间片轮转调度是一种最古老、最简单、最公平且使用最广的调度算法,又称RR(round robin)调度。每个进程被分配一个时间段,称作他的时间片,即该进程允许运行的时间。

**多级反馈队列调度算法:**前面介绍的几种进程调度算法都有一定的局限性。如,短进程优先的调度算法,仅照顾了短进程而忽略了长进程。多级反馈队列调度算法技能使优先级较高的作业得到相应,又能使短进程迅速完成,是目前公认的一种较好的调度方法,UNIX操作系统采用的便是这种调度算法。

优先级调度:为每个流程分配优先级,首先执行具有最高优先级的进程,以此类推。具有相同优先级的进程以先到先服务的调度方式执行。优先级可以根据内存要求、时间要求或其他任何资源要求来确定。

8.线程间的同步方式(多线程同步互斥的常见方法)

线程同步是两个或多个共享资源的线程并发执行时,应该同步线程以避免关键的资源使用冲突。操作系统一般有如下三种线程同步的方式:

互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才允许访问公共资源。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如Java中的synchronized关键字和各种Lock都是这种机制。

**信号量(Semphares):**它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问资源的最大线程数量。信号量的数据结构由一个值和一个指针构成,指针指向等待该信号量的下一个进程,信号量的值与相应资源的使用情况有关。当它的值>0时,表示当前可用资源的数量;<0时,其绝对值表示等待使用该资源的进程个数。

信号量的值仅能通过PV操作来改变:

p操作(wait):申请一个单位资源,进程进入;v操作(signal):释放一个单位资源,进程出来

PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作

**事件(Event) 😗*Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便地实现多线程优先级的比较操作。

9. 协程

协程,是一种基于线程,但又比线程更加轻量级地存在,这种由程序员自己写程序来管理的轻量级线程叫做『用户空间线程』,对内核具有不可见性。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。

而协程的目的就是当出现长时间的I/O操作时,通过让出(yield)目前的协程调度,来消除上下文切换上的开销。通过协程调度的方式,避免了陷入内核级别的上下文切换造成的性能损失,进而突破了线程在IO上的性能瓶颈。从编程上看,协程的本质就是:控制流的主动让出(yield)和恢复(resume)机制。

协程的特点:

协同:线程的切换由操作系统负责调度,协程由用户自己调度,其通过协作而不是抢占来进行切换,减少了上下文切换,提高了效率。

线程的默认Stack大小是1M,而协程更加轻量,接近1K。因此可以在相同的内存中开启更多的协程。

用户态完成创建,切换和销毁。

由于在同一个线程上,因此可以避免竞争关系而使用锁。

适用于被阻塞的,且需要大量并发的场景。但不适用于大量计算的多线程,遇到这种情况,最好使用多线程去解决。

10. 什么是死锁?(死锁进程线程都能出现)

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。例如:有一个线程A,按照先锁a再锁b的顺序获得锁,同时又有一个线程b,按照先锁b再锁a的顺序获得锁,就会造成死锁。

在这里插入图片描述

11. 死锁产生的原因

  1. 系统资源的竞争

​ 当系统中供多个进程共享使用的资源,例如:打印机、公用队列等等,其数目不满足诸进程的需要时,会引起诸多进程的竞争从而产生死锁。

  1. 进程运行顺序推进不当产生死锁

进程推进顺序合法

当进程P1和进程P2并发执行时,如果按照如下顺序推进:P1:Request(R1),P1:Request(R2),P1:Relese(R1),P1:Relese(R2);P2:Request(R2),P2:Request(R1),,P2:Relese(R2),P2:Relese(R1)。这两个进程就可以顺利执行完毕,这种不会引起进程死锁的推进顺序是合法的。

进程推进顺序非法

如果P1保持了资源R1,P2保持了资源R2,系统处于不安全的状态,因为这两个进程再向前推进,就有可能引发死锁。例如:P1继续运行,P1:Request(R2),由于R2已被P2占用而阻塞;当P2运行到P2:Request(R1)的时候,也将因为R1已被P1占用而阻塞,于是发生进程死锁。

12. 产生死锁的四个必要条件

● 互斥条件:该资源任意时刻只能允许一个线程占用。

● 请求与保持条件(占有且等待):一个进程因请求资源而阻塞时,对已获得的资源保持不放。

● 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他程序强行夺走,即:只能由获得该资源的进程自己释放。

● 循环等待条件:指在发生死锁的时候,必然存在一个进程——资源的循环链,即进程集合{P0, P1, ……, Pn}中的P0在等待P1占用的资源,P1在等待P2占用的资源……,Pn在等待P0占用的资源。

这四个条件是死锁产生的必要条件,只要死锁产生,上述条件必然成立;若上述条件有一个不成立,死锁不会产生。

13. 预防死锁的方法

  1. 破坏“占有且等待”条件

​ 所有的进程开始之前,必须一次性申请其在整个运行过程中需要的全部资源

  1. 破坏“不可剥夺”条件

​ 当一个已经占有了一些资源的进程在提出申请新的资源没有得到满足的时候,它必须释放已经保持的所有资源,待以后申请的时候再重新申请。

  1. 破坏“循环等待”条件

​ 可以定义资源类型的线性顺序来预防,将每一个资源进行编号,当进程占有了编号为i的资源时,只能申请编号>i的资源。如图所示:

在这里插入图片描述

14. 如何发现死锁?

通过死锁检测工具,例如jdk工具jps、jstack来排查死锁问题

  1. 使用jps查找程序进行:jps是jdk提供的一个工具,可以查看到正在运行的java程序。

  2. 使用jstack查找程序进行:jstack是jdk提供的一个工具,可以查看java进程中的线程堆栈信息,后面可以查看到具体代码在哪一行。

  3. 也通过jdk提供的工具jconsole排查死锁问题:jconsole是jdk提供的一个可视化的工具,方便排查程序的一些问题,例如:栈溢出、死锁问题等。

15. 死锁的解除

如果利用死锁检测算法检测出了死锁,那么此时就要采取对系统采取相应的措施。常用方法有:

  1. 抢占资源:从一个或多个进程中抢占足够数量的资源分配给死锁进程,以解除死锁状态

  2. 终止(撤销)进程

    a.终止所有的死锁进程 这种方式简单粗暴,但是代价很大,很有可能会导致一些已经运行了很久的进程前功尽弃。

    b.逐个终止,直到死锁解除。该方法的代价也很大,因为每终止一个进程就需要使用死锁检测来检测系统当前是否处于死锁状态。另外,每次终止进程的时候终止那个进程呢?每次都应该采用最优策略来选择一个“代价最小”的进程来解除死锁状态。一般根据如下几个方面来决定终止哪个进程:

    进程的优先级

    进程已运行时间以及运行完成还需要的时间

    进程已占用系统资源

    进程运行完成还需要的资源等。

16. 进程间通信有哪些?优点缺点?

  1. 管道/匿名管道(Pipes)

用于具有亲缘关系的父子进程或兄弟进程之间的通信。在这里插入图片描述
管道的实质:一个内存缓冲区,进程以先进先出的方式从缓冲区存取数据,管道一端的进程顺序地将数据写入缓冲区;另一端的进程则顺序将数据取出。

  1. 有名管道(Names Pipes)

匿名管道由于没有名字,只能用于两个具有亲缘关系的进程进行通信。为了克服这个缺点,提出了有名管道。有名管道严格遵守先进先出原则。有名管道以磁盘文件的形式存在,可以实现本机任意两个进程间通信。

拓展:全双工、半双工、单工通讯的区别:

单工:方向是固定的,只有一个方向可以写,例如广播。(匿名管道)

半双工:方向不固定,但同一时刻只能有一个方向在写,例如对讲机。(有名管道)

全双工:两个方向都可以同时写,例如电话。

  1. 信号量

信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于同步。这种通信方式主要用于解决同步问题,避免竞争条件

  1. 信号

信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

  1. 消息队列

消息队列是消息的链表,存放在内核当中,并由消息队列标识符进行标记。消息队列克服了信号传输信息少缓冲区只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列是UNIX下不同进程间可以实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程。对消息队列有控制权限的进程均可以通过msget操作完成对消息队列的控制。通过使用消息类型,进程可以按照任何顺序读取信息,或为消息安排优先级顺序。

  1. 共享内存

使得多个进程可以访问同一块内存空间,不同进程可以及时查看对方进程在共享内存中更新的数据。这种方式需要依赖某种同步操作,如:信号量互斥锁等。可以说这是最有用的进程间通信方式。

  1. 套接字

此方法主要用于在客户端和服务器之间进行网络通信。套接字是支持TCP/IP网络通信的最小基本操作单元,可以看作是不同主机之间的进程进行双向通信的端点,简单地说,就是通信两方的一种约定,用套接字中的相关函数来完成通信过程。

17. 孤儿进程&僵尸进程

**孤儿进程:**父进程结束了,但它的一个或多个子进程还在运行,那么这些进程就成为了孤儿进程。子进程由init进程回收。

僵尸进程:子进程退出了,但他的父进程没有使用waitwaitpid去获取子进程的信息,子进程的进程描述符仍保存在系统中。

危害:

​ 如果父进程不调用waitwaitpid的话,子进程的信息不会被释放,进程号一直被占用。而系统能产生的进程号是有限的,如果产生大量的僵尸进程,将因为没有新的进程号而无法创建新的进程,这就是僵尸进程的危害。

​ 孤儿进程是没有父进程的进程,它由init进程循环地wait()回收资源,由init进程充当父进程。因此孤儿进程没有什么危害。

**预防方法:**通过信号机制,在处理函数中调用wait,回收资源。

18. 什么是临界资源

临界资源是一次只允许一个进程使用的共享资源。各进程采用互斥的方式,实现共享的资源成为临界资源。属于临界资源的硬件有:打印机、磁带机等;软件有:消息队列、变量、数组、缓冲区等。诸进程采用互斥的方式,实现对这些资源的共享。

19. 什么是临界区

每个进程中访问临界资源的那一段程序称为临界区。每次只允许一个进程进入临界区,进入后不允许其他程序进入。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值