1、进程和线程

厨子大约 13 分钟操作系统原创面试题进程和线程程序厨

1.进程线程

1.0 什么是进程

  • 进程是资源分配的基本单位。

  • 进程是程序在处理器的一次执行过程

  • 进程是可以和别的进程并行执行的计算

  • 是在一个数据集合的运行过程,是系统进行资源分配和调度的一个独立单位

进程的组成

进程控制块PCB:每个进程一个PCB,用来标识进程的存在,又能刻画瞬间特征的数据机构

程序段:能被进程调度到CPU 执行的代码段

数据段:保存原始数据或中间数据。

进程标识符:就好比人类的身份证,用来区分。

进程的当前状态:作为分配资源的依据

程序和数据地址:指出进程的程序和数据所在的地址

进程优先级:反映进程执行优先级。

通信信息:记录和其他进程的通信情况

1.1 为什么说PCB(进程控制块)是进程存在的唯一标识?

PCB是操作系统为每个进程分配的一个数据结构,其作用是使程序可以独立执行。

PCB中存着进程执行的程序和数据内存地址,进行内存访问,通信时也需要访问PCB,进程暂停执行时,也会将状态保存在PCB中,系统总是通过PCB对进程进行控制。说白了,PCB就好像进程的管家。

1.2 进程的状态与转换

1.3 进程和线程比较

一个进程可以创建很多子进程。

进程和线程的比较

这一块是常考题目

我们主要从调度,拥有资源 ,并发性,系统开销等方面对其进行比较

调度:在传统的操作系统中,拥有资源和独立调度的单位都是进程,引入线程之后,调度的最小单位就变成了线程,但是拥有资源的最小单位还是进程,另外在同一个进程中,线程的切换不会影响进程,但是不同的进程中的切换则会引起进程切换。

拥有资源:不论是传统的操作系统,还是设有线程的操作系统,进程都是资源分配的最小单位。

并发性:在引入线程的操作系统中,不仅进程之间可以并发,线程之间也可以并发,这使得操作系统具有更好的并发性。

系统开销:创建进程或撤销进程的同时,系统都要为之分配或回收资源,在进行进程切换时,涉及当前进程CPU 环境的保存和新环境的设置,线程切换时,只需保存和设置少量寄存器内容,因此开销很小。总的来说就是线程间切换的开销更小,同步和通信很容易实现。

推荐阅读:https://www.zhihu.com/question/25532384open in new window

1.4 线程模型

多对一模型:多个用户级线程映射到一个内核级线程上

一对一模型:一个用户级线程映射到一个内核级线程上,堵塞时不会影响其他线程的运行。

多对多模型:不仅可以使多个用户级线程真正意义上并行执行,而且不会限制用户线程的数量。

1.5 进程切换

进程切换的速度是远小于线程切换的,举个不太恰当的例子,我们如果把进程比作房子,线程比作卧室的话,线程切换则是在每个卧室之间,来回穿梭,不用更换衣物,鞋子,但是我们如果要去邻居家(另一个进程)那么则需要更换衣服鞋子,这就是线程切换和进程切换。

上下文切换,保存当前情况,将运行情况存到PCB中等

进程切换为什么慢?

这就需要说到虚拟地址的地方了,因为每个进程都有自己的虚拟地址空间,然后线程是共有进程的虚拟空间,所以进程切换的话需要虚拟地址空间的切换。这个过程是比较慢的。

另外进程通过查找页表,将虚拟空间映射到物理地址空间。这个过程是比较慢的,所以通常使用Cache来保存那些经常被查找的地址映射,然后进程切换的话,也会导致页表的切换,进而导致Cache失效,命中率降低,进而就会导致程序运行变慢。

推荐阅读:https://zhuanlan.zhihu.com/p/258956479open in new window

1.6 协程

协程又叫微线程,

在有大量IO操作业务的情况下,我们采用协程替换线程,可以到达很好的效果,一是降低了系统内存,二是减少了系统切换开销,因此系统的性能也会提升。

协程多用于异步I/O这样性能最好,堵塞I/O不能完全发挥出优势。

我们可以把协程理解成用户态的线程,操作系统不知道协程的存在,所以协程切换时不需要由操作系统控制,可以由自己控制,这样就节省了操作系统资源。

另外一个线程可以由多个协程,是线程内调度的基本单位,然后有自己的寄存器。

推荐阅读:https://zhuanlan.zhihu.com/p/337978321open in new window

1.7 上下文切换的过程

  • 挂起一个进程,将这个进程在CPU中的状态(上下文信息)存储于内存的PCB中。
  • 在PCB中检索下一个进程的上下文并将其在CPU的寄存器中恢复。
  • 跳转到程序计数器open in new window所指向的位置(即跳转到进程被中断时的代码行)并恢复该进程

推荐阅读:https://zhuanlan.zhihu.com/p/99923968open in new window

进程通信和线程通信

1.8 进程通信

进程通信就是指进程间的信息交换

  • 管道
  • 消息队列
  • 共享内存
  • 信号量
  • 信号
  • Socket

管道

ps auxf | grep mysql

中间的 | 就是管道,匿名管道但是只能单向传输。然后只能在父子进程之间进行传输。

命名管道,可以在无关系的进程之间进行传输。

管道通信,效率较低。

消息队列

消息队列 的通信模式就可以解决。比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。消息队列是保存在内核中的消息链表

缺点通信不及时,并且有大小限制

共享内存

image-20211012151937103
image-20211012151937103

这个比较有意思,就是拷贝来拷贝去,进行拷贝,有点类似留言板的功能

并发情况下会出问题

信号量

PV操作,用于多进程的情况,P操作为减 1 ,看看资源是否已经被调用,信号量就是为了解决并发情况下的安全性,和加锁原理类似。

信号

异常状态下的进程间通信,可以使用 kill -l 查看,给进行发信号,让其执行某些命令,比如 kill - 9 pid 就是

socket

不同主机间的进程通信

推荐阅读:https://zhuanlan.zhihu.com/p/165224175open in new window

写的非常牛批

1.9 线程通信

wait notify

加锁

volatile等

共享内存

进程调度

1.10 进程调度的准则

CPU利用率:如何调度可以使CPU的利用率达到最大

系统吞吐率:系统吞吐量表示单位时间内CPU完成作业的数量

响应时间:调度策略要尽量保证响应时间在用户接受的范围内

周转时间:周转时间是作业从开始到完成的所需的时间,尽量使这个时间较小。

1.11 进程调度算法

进程调度含义:当某一个进程正在处理器上执行时,这时来了一个新的更紧急的进程,我们此时应该如何调度。

调度分为抢占式方式非抢占式方式。

抢占式:很容易理解,当一个进程正在执行时,又来了一个优先级较高的进程进入就绪队列,则立即停止当前进程,然后将处理器分配给优先级更高的进程。

非抢占式:来了优先级更高的进程时,我继续执行,等我执行完了之后,新进程再继续执行。

常见的进程调度算法

1.先来先服务:根据进入就绪队列的顺序来执行,该方法分为非抢占式,比较公平。用的不太多了

2.短作业优先调度:这个方式就是把CPU分配给能够最快完成工作的进程。

3.优先级调度:这个是常用的进程调度算法,基本思想就是将CPU分配给优先级最高的进程。这个优先级是在进程创建时确定的,确定之后在运行期间不再改变。

4.时间片轮转调度算法:将所有就绪进程排成一个队列,进程调度程序总是选择第一个进程执行,每个进程执行的时间相同,所以时间片的大小设定就比较重要。

5.高响应比 :综合了先来先服务和短作业优先两种调度算法的特点。考虑了等待时间和执行时间两个因素。

响应比 = (作业等待时间+估计执行时间)/ 估计执行时间

选择响应比高的进行执行

6.多级队列调度算法 将就绪的进程分到多个队列中去,每个进程属于一个队列,每个队列采用一种调度算法。

7.多级反馈队列调度算法:多级反馈调度是时间片轮转和优先级调度算法的综合与发展,多个队列中的优先级不同,时间片轮转的大小也不一样。通常是优先级越高,执行的时间片越短,刚开始按照先来先服务准则,心来的一个新进程是放在最后一个队列的末尾,如果在该时间片内不能执行完毕,则将其移到上一个优先级的队列末尾,继续排队。

推荐阅读:https://zhuanlan.zhihu.com/p/225162322open in new window

1.12 同步与互斥

推荐阅读:https://zhuanlan.zhihu.com/p/161936748open in new window

1.13 进程同步

直接相互制约,某一进程若是收不到另一进程给他提供的必要信息就不能继续执行下去。

1.14 进程互斥

间接相互制约,某个进程要使用某个资源,但是这个资源被另一个进程使用,所以该进程只能等另一个进程使用完毕,才能继续使用。

消费者和消费者之间就是互斥关系,消费者和生产者之间就是同步关系

1.15 临界资源和临界区

同时只能允许一个进程访问的资源,统称为临界资源。

临界区是临界资源的一部分,临界资源可以分为进入区,临界区,退出区,剩余区

进入区:好比加锁区,告诉别人里面已经有人了,不要进来了。

临界区:进程中用于访问临界资源的代码

退出区: 清除正在临界区内的标志,解锁区。

1.16 如何防止两个进程进入临界区

很容易理解,我们可以用白话文来回答

闲时让进:空闲状态你可以进入

忙则等待:有人正在用,你等一等

有限等待:不会让你一致等的放心好啦。

让权等待:你出问题了,就别占着位置啦,让别人用吧。

1.17 同步和互斥实现和经典例子

互斥:加锁,信号量

同步:信号量

经典同步问题:消费者-生产者问题

一组生产者像一组消费者提供产品,他们共享一个缓冲区,生产者会向里面投放物品,消费者从里面取走产品。

但是这个里面存在一个问题,那就是缓冲区内没有物品,消费者不断取的过程,和已经满了生产者不断放入的情况,还有就是多个消费者取的情况。这时我们可以设置三个信号量,一个是是满,一个是空,一个是单一访问(多消费者,多生产者情况)。

读者写者问题

一块黑板,老师们只往上面写,学生只能读。

读者写者问题有点像我们的读锁和写锁。

可以多个读者同时读,但是只能有一个写者同时写。

如果写者正在写,此时不允许其他人读和写。

当读者正在读的时候,写者不能写

解决方法:读者和写者互斥,可以多个读者同时进入,只能由一个写者进入,写者进入时,读者不能进入。

哲学家进餐问题

5 个哲学家围坐在一起,桌上放着 5 个筷子,每两个哲学家之间放一根,我们此时思考一下,如果五个人同时只拿起自己左边或右边的筷子,那么这样他们每个人只有一个筷子,这样就会造成都没有机会进餐。也就是死锁的情况。

我们如何保证哲学家吃饭的工作有序进行,而不会出现没有饭吃的情况。

第一种解决方法:可以加个信号量,每次只允许一个人就餐,当某个人就餐时,其他人要等他就餐完毕才能获得筷子。

这种方法是低效的,因为只能有一个人进餐,但是我们一共有五个筷子,理论上可以两个人可以同时就餐。

那我们可以这样解决

给哲学家编号,让奇数号先取左边,再取右边,偶数号先取右边,再取左边。我们发现 1,2哲学家竞争 1 号筷子,3,4哲学家竞争 3 号筷子,1,5哲学家竞争 5 号筷子,竞争的都是奇数位筷子,最后肯定有两个人可以获得进餐机会,然后让没能进餐的进入队列即可。

1.18 管程

用来管理进程的工具,防止进程访问共享资源时,产生死锁的情况。