DJ2-4 进程同步(第二节课)
创始人
2025-06-01 03:54:16
0

目录

2.4.3 信号量机制

1. 整型信号量

2. 记录型信号量

3. AND 型信号量

4. 信号量集

三种特例

2.4.4 信号量的应用

1. 利用信号量实现进程互斥

2. 利用信号量实现前趋关系

2.4.5 管程机制

1. 管程的组成

2. 管程的主要特点


2.4.3 信号量机制

信号量(Semaphores)机制:是一种卓有成效的进程同步工具。

1. 整型信号量

把整型信号量定义为一个用于表示资源数目的整型量 S,仅能通过两个标准的原子操作 wait(S) 和 signal(S) 来访问。这两个原子操作又分别被称为 P 和 V 操作,注意必须使用大写。

wait(S) {while(S <= 0);  //do no-op,CPU空转S--;            //访问资源,资源减一
}signal(S) {S++;            //释放资源,资源加一
}

在 wait(S) 中,对 S 值的测试和做 S=S-1 操作时都是不可中断的。

2. 记录型信号量

整型信号量的问题:忙等,即当 wait(S) 中信号量 S<=0 时,会不停地进行测试,因此未遵循让权等待的原则。而记录型信号量机制则是一种不存在 “忙等” 现象的进程同步机制。

记录型信号量的数据结构可描述如下:

typedef struct {int value;struct process_control_block * list;
} semaphore;

原子操作 wait(S) 和 signal(S) 可描述如下:

wait(semaphore * S) {S->value--;if(S->value < 0) block(S->list);//S->value == 0时代表刚好取走最后一个资源
}signal(semaphore * S) {S->value++;if(S->value <= 0) wakeup(S->list);//S->value == 0时代表刚好还有一个进程被阻塞
}

整型信号量和记录型信号量的问题:

  • 只能有效地解决多个进程共享一种临界资源的情况
  • 即只需要设置一个临界区

下面来看多个进程需要访问多种临界资源的情况。假设进程 A 和 B 需要访问共享数据 D 和 E,设置互斥型信号量 Dmutex 和 Emutex,两者初始值均为 1,进程 A 和 B 的访问操作如下:

process A:         |process B:
wait(Dmutex);      |wait(Emutex);
wait(Emutex);      |wait(Dmutex);
signal(Emutex);    |signal(Dmutex);
signal(Dmutex);    |signal(Emutex);

若进程 A 和 B 按下述次序交替执行 wait 操作:

process A: wait(Dmutex);    //Dmutex=0
process B: wait(Emutex);    //Emutex=0
process A: wait(Emutex);    //Emutex=-1, A blocked
process B: wait(Dmutex);    //Dmutex=-1, B blocked

进程阻塞以后也不能释放已持有的资源。最后,进程 A 和 B 就将处于僵持状态。在无外力作用下,两者都将无法从僵持状态中解脱出来。我们称此时的进程 A 和 B 已进入死锁状态。

3. AND 型信号量

AND 同步机制的基本思想:将进程在整个运行过程中需要的所有资源,一次性全都地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源也不分配给它。

对若干个临界资源的分配采取原子操作:要么把它所请求的资源全部分配到进程,要么一个也不分配。具体方法是在 wait 操作中,增加了一个 “AND” 条件,故称为 AND 同步,或称为同时 wait 操作(simultaneous wait)。

Swait 操作定义如下:

Swait(S1, S2, ... , Sn) {while(true) {if(S1 >= 1 && S2 >= 1 && ... && Sn >= 1) {for(i = 1; i <= n; ++i) Si = Si - 1;break;  //分配完资源后,直接退出while循环} else {/*place the process in the waiting queue associated withthe first Si found with Si<1, and set the program countof this process to the beginning of Swait operation*/}}
}

Ssignal 操作定义如下:

Ssignal(S1, S2, ... , Sn) {for(i = 1; i <= n; ++i) Si = Si + 1;/*remove all the process waiting in the queueassociated with Si into the ready queue*/
}

4. 信号量集

在每次分配时,采用信号量集来控制,可以分配多个资源。

Swait 操作定义如下:

Swait(S1, t1, d1, ... , Sn, tn, dn) {while(true) {if(S1 >= t1 && ... && Sn >= t1) {for(i = 1; i <= n; ++i) Si = Si - di;break;  //分配完资源后,直接退出while循环} else {/*place the process in the waiting queue associated withthe first Si found with Si

Ssignal 操作定义如下:

Ssignal(S1, d1, ... , Sn, dn) {for(i = 1; i <= n; ++i) Si = Si + di;/*remove all the process waiting in the queueassociated with Si into the ready queue*/
}

三种特例

1)Swait(S, d, d):只有一种信号量 S,允许进程每次申请 d 个资源,当现有资源少于 d 时,不予分配。

2)Swait(S, 1, 1):只有一种信号量 S,允许进程每次申请 1 个资源,当现有资源少于 1 时,不予分配。当 S = 1 时,代表资源总量为 1,从而信号量集退化为互斥信号量;当 S > 1 时,代表资源总量大于 1,从而信号量集退化为记录型信号量。

3)Swait(S, 1, 0):可控开关。当 S >= 1 时,允许多个进程进入某特定区;当 S = 0 时,将阻止任何进程进入特定区。

读写文件举例:允许多个读进程进入临界区,但一旦有一个写进程进入临界区,则将阻止任何进程进入临界区。

P0:Swait(S, 1, 0)  //S>=1成立,且不改变信号量
P1:Swait(S, 1, 0)  //S>=1成立,且不改变信号量
Pw:Swait(S, 1, 1)  //S>=1成立,且S-1=0
P2:Swait(S, 1, 0)  //S>=1不成立

2.4.4 信号量的应用

1. 利用信号量实现进程互斥

为使多个进程能互斥地访问某临界资源,只须为该资源设置一互斥信号量 mutex,并设其初始值为 1,然后将各进程访问该资源的临界区 CS 置于 wait(mutex) 和 signal(mutex) 操作之间即可。

  1. 设置一互斥信号量 mutex
  2. 设其初始值为 1
  3. 将临界区 CS 置于 wait(mutex) 和 signal(mutex) 之间

利用信号量实现两个进程互斥的描述如下:

  • mutex 互斥
  • semaphore 信号量
  • 老师用 Pascal 写的,我不能保证我语法正确
var mutex:semaphore:=1; //将mutex定义为semaphore类型,且赋初值为1
begin
parbeginprocess1: beginrepeatwait(mutex);//critical sectionsignal(mutex);//remainder sectionuntil falseendprocess2: beginrepeatwait(mutex);//critical sectionsignal(mutex);//remainder sectionuntil falseendparend
end

注意:

  • 对于互斥型信号量,wait(mutex) 和 signal(mutex) 必须成对出现;
  • 缺少 wait(mutex) 导致系统混乱,不能保证对临界资源的互斥访问;
  • 缺少 signal(mutex) 会使临界资源永远不被释放,等待该资源的进程不能被唤醒。

2. 利用信号量实现前趋关系

利用信号量来描述程序或语句之间的前趋关系。

其中,Si 是需要执行的语句。

p1(){ S1; signal(a); signal(b); }
p2(){ wait(a); S2; signal(c); signal(d); }
p3(){ wait(b); S3; signal(e); }
p4(){ wait(c); S4; signal(f); }
p5(){ wait(d); S5; signal(g); }
p6(){ wait(e); wait(f); wait(g); S6; }void main() {semaphore a, b, c, d, e, f, g;//将信号量初值均设置为0,若后续进程试图执行则必被阻塞a.value = b.value = c.value = 0;d.value = e.value = f.value = g.value = 0;cobegin  //采用并行执行p1(); p2(); p3(); p4(); p5(); p6();coend;
}

2.4.5 管程机制

当共享资源用共享数据结构表示时,资源管理程序可用对该数据结构进行操作的一组过程来表示(例如,资源的请求过程 request 和释放过程 release),我们把这样一组相关的数据结构和过程一并称为管程(monitors)。
Hansan 为管程所下的定义是:“一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据”。

1. 管程的组成

  • 管程的名字
  • 局部于管程的共享变量说明
  • 对该数据结构进行操作的一组过程
  • 对局部于管程的数据设置初始值的语句

Monitor(管程)—— 面向对象方法  

2. 管程的主要特点

局部数据变量只能被管程的过程访问,任何外部过程都不能访问。

一个进程通过调用管程的一个过程进入管程。

在任何时候,只能有一个进程在管程中执行,调用管程的任何其他进程都被挂起,以等待管程变成可用的。

相关内容

热门资讯

【MySQL】锁 锁 文章目录锁全局锁表级锁表锁元数据锁(MDL)意向锁AUTO-INC锁...
【内网安全】 隧道搭建穿透上线... 文章目录内网穿透-Ngrok-入门-上线1、服务端配置:2、客户端连接服务端ÿ...
GCN的几种模型复现笔记 引言 本篇笔记紧接上文,主要是上一篇看写了快2w字,再去接入代码感觉有点...
数据分页展示逻辑 import java.util.Arrays;import java.util.List;impo...
Redis为什么选择单线程?R... 目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程?三、R...
【已解决】ERROR: Cou... 正确指令: pip install pyyaml
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
Lock 接口解读 前置知识点Synchronized synchronized 是 Java 中的关键字,...
Win7 专业版安装中文包、汉... 参考资料:http://www.metsky.com/archives/350.htm...
3 ROS1通讯编程提高(1) 3 ROS1通讯编程提高3.1 使用VS Code编译ROS13.1.1 VS Code的安装和配置...
大模型未来趋势 大模型是人工智能领域的重要发展趋势之一,未来有着广阔的应用前景和发展空间。以下是大模型未来的趋势和展...
python实战应用讲解-【n... 目录 如何在Python中计算残余的平方和 方法1:使用其Base公式 方法2:使用statsmod...
学习u-boot 需要了解的m... 一、常用函数 1. origin 函数 origin 函数的返回值就是变量来源。使用格式如下...
常用python爬虫库介绍与简... 通用 urllib -网络库(stdlib)。 requests -网络库。 grab – 网络库&...
药品批准文号查询|药融云-中国... 药品批文是国家食品药品监督管理局(NMPA)对药品的审评和批准的证明文件...
【2023-03-22】SRS... 【2023-03-22】SRS推流搭配FFmpeg实现目标检测 说明: 外侧测试使用SRS播放器测...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
初级算法-哈希表 主要记录算法和数据结构学习笔记,新的一年更上一层楼! 初级算法-哈希表...
进程间通信【Linux】 1. 进程间通信 1.1 什么是进程间通信 在 Linux 系统中,进程间通信...
【Docker】P3 Dock... Docker数据卷、宿主机与挂载数据卷的概念及作用挂载宿主机配置数据卷挂载操作示例一个容器挂载多个目...