0%

操作系统-进程间通信

进程间通常需要相互通信,那么进程间是如何进行信息传递的呢?怎么确保多个进程在关键活动中不会出现交叉?怎样保证进行活动是按照想要的顺序执行的呢?

相关概念:

  • 竞争条件:两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序。
  • 临界区:对共享内存(数据)进行访问的程序片段。
  • 优先级翻转:针对不同优先级的进程访问同意临界区,由于调度规则限定只要高优先级处于就绪状态就可以运行,若某一时间低优先级进程先行进入临界区,且尚未离开,此时高优先级处于就绪状态,由于低优先级不会再次被调度,高优先级进程将一直处于等待状态。

1 互斥方案

互斥方案用于保证当一个进程在临界区操作时,其他进程不会进入临界区。

1.1 屏蔽中断

屏蔽中断即每个进程一进入临界区立即屏蔽所有中断,然后在离开前再打开中断。

缺点:

  • 将屏蔽中断的权利交予用户进程,不可控因素太多,若进程屏蔽后未及时打开,可能导致系统崩溃;
  • 对于多处理器,仅对当前运行CPU有效;

1.2 锁变量

锁变量法是一种软件解决方案,其思想为设置一个共享锁变量,为其设置初始值(假设为0),当一个进程进入临界区,它将首先检测锁变量的值是否为0,若是,则将锁变量的值设置为加锁值(假设为1);若非0,则进行等待。

缺点:该方法不能彻底解决互斥问题,若进程A读取锁变量值为0,且未解锁,此时CPU调度进程B,此时进程B读取锁变量也将为0。

1.3 严格轮换法

严格轮换法的思想是要求两个进程严格第轮流进入他们的临界区。如下图所示:

严格轮换法示例

1.4 Peterson解法

Peterson算法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define FALSE 0
#define TRUE 1
#define N 2 // 进程数量

int turn; // 当前轮到哪个进程
int interested[N]; // 所有值初始化为0

void enter_region(int process) // 准备进入临界区的进程号
{
int other; // 其他进程号
other = 1 - process; //另一方进程
interested[process] = TRUE; // 标识感兴趣
turn = process; // 设置标识;
while(turn == process && interested[other] == TRUE); // 等待;
}

void leave_region(int process) // 离开临界区的进程号
{
interested[process] = FALSE;
}

1.5 TSL指令

通过硬件加锁的方式,使用命令TSL RX,LOCK将一个内存字lock读到寄存器RX中,然后在该内存地址上存一个非零值。执行该指令的CPU将锁住内存总线,以禁止其他CPU在本指令结束之前访问内存。

锁住存储总线和屏蔽中断有什么区别?

  • 屏蔽中断:对于多处理器无效,仅会屏蔽当前处理CPU。

  • 锁住总线:通过一个特殊的硬件设备,保证其他处理器也无法使用。

2 信号量

信号量使用一个整型变量来累计唤醒次数,其取值可以为0(标识没有被保存下来的唤醒操作)或正值(标识有一个或多个唤醒操作)。

信号量有两种操作:

  • down(sleep)-P操作:
    • 信号量的值大于0:将值减1并继续;
    • 信号量的值等于0:将进程将睡眠,此时down操作并未结束。
  • up(wakeup)- V操作:对信号量的值增加1。有一个或多个进程在该信号量上睡眠,无法完成先前的down操作,则由系统选择一个,并允许该进程完成它的down操作。