操作系统面试高频知识点归纳(一):进程与线程、死锁、进程调度、状态转换、守护孤儿僵尸进程

进程与线程

1、进程与线程区别
2、进程间通信
3、线程间通信
4、fork()与vfock()区别
5、死锁
6、进程调度算法
7、进程的状态与转换
8、守护进程、孤儿进程、僵尸进程

1、进程与线程区别

(1)进程是系统资源分配的基本单位,线程是CPU资源调度基本单位。
(2)一个进程可以有多个线程,而一个线程只属于一个进程;
(3)进程有独立的内存空间,而多个线程共享进程的内存;
(4)进程互不影响,同一个进程下的一个线程挂掉会导致整个进程挂掉;
(5)进程的系统开销大,线程系统开销小;
(6)由于同一进程的多线程共享内存空间,线程通信较容易,而进程通信较复杂。


2、进程间通信

进程之间交换数据是在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区(A和B的公共资源),进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

(1)管道

属于半双工通信(数据只能单向通信),是面向字节流的,将上一个命令的输出作为下一个命令的输入,由多个命令配合完成一件事情。
管道分为无名管道(PIPE)和命名管道(FIFO),无名管道用于有亲缘关系进程通信,命名管道可用于无亲缘关系进程通信。
(a)管道的创建
管道是调用pipe函数创建:
#include <unistd.h>
int pipe (int fd[2]);//成功返回0,出错返回-1
fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。
(b)管道通信过程
父进程创建管道,得到两个文件描述符指向管道的两端
父进程fork()出子进程,子进程也有两个文件描述符指向同一管道。
父进程关闭管道读端(fd[0]),子进程关闭写端(fd[1])。管道是闭环队列实现,数据从写端流入,从读端流出,实现进程间通信。

(2)消息队列

消息队列,是消息的链接表,存放在内核中。 主要特点:
生命周期随内核,消息队列会进程终止,消息队列及其内容不会被删除;
消息队列可以双向通信;
面向记录的,可按消息类型读取,不一定先进先出;

(3)信号量

信号量是一个计数器,它控制多个进程对共享资源的访问;信号量不是用于存储进程通信数据,用于实现进程间互斥与同步。
(a)为什么要使用信号量
为了防止多个进程同时访问一个共享资源,信号量可以让一个临界区同一时刻只有一个执行流在访问它。
(b)信号量的工作原理
多进程访问共享资源时,按照以下步骤:
检测控制该资源的信号量值;
若此信号量的值为正,则进程可以使用该资源,使用后将信号量值减1,表示一个资源被使用。
若此信号量的值为0,则进程进入休眠状态,直至信号量值大于0,进程被唤醒,从新进入第1步。
当进程不再使用由一个信号控制的共享资源时,该信号量值增1,如果有进程正在休眠等待该信号量,则会被唤醒。

(4)信号

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

(5)共享内存

共享内存允许多个进程访问同一块内存空间,是两个正在运行的进程之间数据共享和数据传递的一种非常有效的方式,不同进程可以及时看到对方进程对共享内存中的数据更新。这种方式需要依靠互斥(互斥锁)与同步(信号量)。
特点:
共享内存是最快的一种进程通信(IPC),因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

(6)套接字Socket

Socket套接字用于不同主机间的进程通信,连接过程:三次握手与四次挥手。


3、线程间通信

线程之间通信的两个基本问题是互斥和同步。
(1)全局变量
进程中的线程间内存共享,这是比较常用的通信方式和交互方式。定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。
(2)Message消息机制
常用的Message通信的接口主要有两个:PostMessage和PostThreadMessage,
PostMessage为线程向主窗口发送消息。而PostThreadMessage是任意两个线程之间的通信接口。
(3)事件对象
CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步。


4、fork()与vfock()区别

(1) fork ( )子进程复制父进程数据段和代码段 ;vfork( )子进程与父进程共享数据段 ;
(2)fork ( )父、子进程的执行次序不确定;vfork保证子进程先运行,在调用exit ()之前 与父进程共享数据(在父进程空间中执行)。
(3)vfork( )保证子进程先运行,子进程exit ( )前父进程不会被调度。如果在调用exit ()之前子进程依赖于父进程的进一步动作,则会导致死锁。


5、死锁

死锁是由于多个进程(或线程)在执行过程争夺资源,造成相互等待的僵局现象,若无外力作用,这些进程(线程)将无法向前推进。
死的四个必要条件:(发生死锁,以下条件必然成立;四个条件都满足,发生死锁)
(1)互斥条件
某个资源同一时刻只能被一个进程访问,其他进程访问时要等待。
(2)不可剥夺条件
进程未使用完所获得资源,不能被其他进程剥夺,只能自己主动释放。
(3)请求和保持条件
进程对正在被其他进程占有的资源发出请求,此时请求阻塞(se),但该进程已经占有的资源不会释放。
(4)循环等待条件
进程发生死锁,必然存在一个进程——资源的循环链,链中每一个进程所占有的资源被链中下一个进程请求。
预防死锁:破坏四个必要条件中一个,一般互斥是无法破坏的,故破坏后三个。


6、进程调度算法

(1)先来先服务(FCFS,first come first served )
FCFS根据进程请求先后顺序执行,不考虑等待时间和执行时间,会产生饥饿现象。
属于非抢占式调度,优点是公平,实现简单;缺点是不利于短进程(等待时间久)。
(2)短作业优先(SJF,Shortest Job First )
即最短进程优先,是对FCFS算法的改进。
优点是缩短进程等待时间,缺点是未考虑作业紧迫性,对长进程不利。
(3)优先级调度(HPF)
为每个进程分配一个优先级,按优先级高低进行调度执行。
(4)时间片轮转算法(RR,Round-Robin)
每个进程被分配一个时间片,即该进程允许运行的时间。
所有进程按先来先服务(FCFS)的原则排成一个队列,每次调度把CPU时间分配给队首的进程,该进程可以执行一个时间片。当时间片用完时,并将它送往队列末尾,继续把CPU时间分配给新的队首的进程
时间片轮转算法的效率和时间片大小有关,时间太短使进程切换频繁,花费时间;时间太长,不能保证实时性。
(5)多级反馈队列调度(MFQ)
将时间片轮转与优先级调度相结合,把进程按优先级分成不同的队列
先按优先级调度;优先级相同,按时间片轮转;
优点是兼顾长短作业,有较好的响应时间,可行性强,适用于各种作业环境。


7、进程的状态与转换

进程五种状态:
创建态:运行进程前,需要进行一系列初始化,新建一个进程;
就绪态:进程具备运行状态,已分配到所需资源,只要分配到CPU就能运行;
运行态:进程正在CPU上执行;
阻塞态:因为等待某一事件而暂时不能运行;
终止态:进程已经结束。

8、守护进程、孤儿进程、僵尸进程

(1)守护进程
脱离终端在后台运行的进程。通常情况下守护进程在系统启动时就在运行。
(2)孤儿进程
父进程退出,而它的那些仍在运行子进程称为孤儿进程。孤儿进程将被init进程(进程号PID=1)所收养,并由init进程对它们处理。
(3)僵尸进程
子进程退出,而父进程并没有调用wait( )获取子进程的状态信息,那么子进程就变成僵死进程。
僵尸进程是一个早已死亡的进程,是每一个进程必然会经历的进程阶段。在每个进程调用exit( )退出时,会释放掉大部分资源,但保留了一定信息,包括:
进程号PID
进程状态
运行时间
父进程调用wait( )就是获取子进程的状态信息,以便进行释放。可以用ps命令查看僵尸进程的状态。
危害:
不调用wait(),保留的进程信息就不会被释放 ,进程号一直被占用,最终导致没有可用的进程号而不能产生新进程。
解决办法:
方法1. 子进程退出时向父进程发送SIGCHILD信号,父进程收到该信号进行处理。
方法2. fork ( )两次,将子进程变为孤儿进程,从而父进程变为init进程,通过init进程可以处理僵尸进程(init进程是所有进程的父进程,可以启动其他所有进程)。
两次fork( )原理:
父进程第一次fork()产生子进程,随后父进程执行wait()等待子进程结束;
子进程第二次fork()产生孙子进程,随后子进程执行exit( )退出;
孙子进程失去了父进程,父进程与孙子进程无继承关系了,孙子进程变为孤儿进程,被init进程收养,这样就不会产生僵尸进程了。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值