用信号量实现进程互斥, 同步, 前驱关系

发布于:2023-01-10 ⋅ 阅读:(289) ⋅ 点赞:(0)

在这里插入图片描述
回顾:

信号量
对应一种资源
信号量的value:
资源的剩余数量
如果小于0表示有进程在等待该资源
P操作:
申请一个资源
如果资源不够就阻塞该进程
V操作
释放一个资源
并检查是否仍有进程等待该资源, 有则唤醒一个进程

实现进程互斥

步骤

  1. 确定临界区
    即确定哪段代码用于访问临界资源

  2. 设置 互斥信号量 mutex, 并初始化

  3. 进入区进行P(mutex)操作以申请资源
    回顾进程互斥的四个逻辑部分
    在这里插入图片描述

  4. 退出区进行V(mutex)操作以释放资源
    在这里插入图片描述

英文翻译:
mutex: 互斥体
semaphore: 信号量

使用semaphore mutex方式定义信号量一般认为是记录型信号量
typedef struct {
	int value;
	struct process *L;
}semaphore;

注意事项

  1. 使用semaphore mutex方式定义信号量一般认为是记录型信号量
  2. 对于不同的临界资源需要设置不同的互斥信号量
  3. PV操作必须成对出现
    缺少P则无法保证临界资源的互斥访问
    缺少V则导致资源无法被释放, 且等待进程无法被唤醒

实现进程同步

回顾

什么是进程同步?
由于进程的并发执行导致的异步的特性, 我们无法确定不同进程中指令的执行顺序
为什么需要进程同步?
比如进程1的指令1必须要在进程2的指令3后面执行, 这时候就需要我们提供进程同步机制来实现

如何利用PV操作来实现进程同步?

考虑P操作中资源数为0时的情况
在这里插入图片描述
先对value–, 然后发现value<0, 该进程阻塞

所以我们可以利用如上特性, 阻止代码的执行

实现进程同步的步骤

  1. 确定需要进行进程同步的地方,
    即哪部分要在前面执行,
    哪部分要在后面执行

  2. 设置同步信号量S, S.value初始化为0

  3. 添加PV操作
    先执行的代码的末尾添加V(S)操作
    后执行的代码的开头添加P(S)操作

semaphore S = 0;

P1 ( ) {
	代码1;
	代码2;
	V(S);
	代码3;
}

P2 ( ) {
	P(S);
	代码4;
	代码5;
	代码6;
}

如上代码中, 代码1,2必然在代码4,5前执行

在没有执行V(S)之前, S=0, 直接执行P(S)
会阻塞该进程

除非执行了V(S)使得S.value++后才能顺利执行P(S)以后的内容

实现进程的前驱关系

利用进程同步中得到的总结:
先执行的代码的末尾添加V(S)操作
后执行的代码的开头添加P(S)操作
在这里插入图片描述

图中:

  • Sn为Pn进程中的某个指令
  • x—>y表示x在y前执行
  • abcdefg分别为自己创建的信号量且他们的value初始都为0
  • V(a)—>P(a)表示在S1执行末尾添加V(a)操作, 在S2开始前添加P(a)操作, 其他同理

总结

在这里插入图片描述
使用信号量实现进程同步与进程的前驱关系时, 特别要注意总结出来的结论:

  1. 先执行的代码的末尾添加V(S)操作
  2. 后执行的代码的开头添加P(S)操作
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到