2-3进程管理-进程同步

news2024/11/24 18:39:25

文章目录

  • 一.进程同步、互斥
  • 二.实现临界区互斥的基本方法
    • (一)软件实现方法
    • (二)硬件实现方法
  • 三.互斥锁
  • 四.信号量机制
  • 五.经典同步问题
    • (一)生产者-消费者问题
    • (二)读者-写者问题
    • (三)哲学家进餐问题
    • (四)吸烟者问题
  • 六.管程

一.进程同步、互斥

不同的进程之间存在什么关系?进程之间存在同步和互斥的制约关系。
1.同步
也称直接制约关系,指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。
2.互斥
也称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。

遵循原则:空闲让进、忙则等待、有限等待、让权等待(不能进入临界区时应当释放处理器)

3.临界资源的访问过程分为四个部分
(1)进入区
“上锁”。为了进入临界区使用临界资源,在进入区要检查可否进入临界区,若能进入临界区,则应设置正在访问临界区的标志,以阻止其他进程同时进入临界区
(2)临界区
进程中访问临界资源的那段代码,又称临界段
(3)退出区
“解锁”。将正在访问临界区的标志清除
(4)剩余区
代码中的其余部分

4.为什么要引入进程同步的概念?
在多道程序共同执行的条件下,进程与进程是并发执行的,不同进程之间存在不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步的概念

二.实现临界区互斥的基本方法

(一)软件实现方法

1.单标志法
在这里插入图片描述
第③步让给P1使用,若P1一直不使用,P0也会卡住。
违背“空闲让进”

2.双标志法先检查
flag[0]=true表示P0想进入临界区
flag[1]=true表示P1想进入临界区
双方先检查对方是否想进入,若不,表明自己进入意愿。若按①⑤②⑥的顺序执行代码,则二者同时进入临界区。
违背“忙则等待”
原因:“检查”和“上锁”不是一气呵成的
在这里插入图片描述

3.双标志法后检查
按①⑤②⑥的顺序执行,双方同时上锁,②⑥不断循环,双方都无法进入临界区
违背“空闲让进”、“有限等待”

在这里插入图片描述

4.Peterson算法

②表示P0谦让,⑦表示P1谦让,最后做出谦让的需等待

最后谦让方卡在while循环上不断检查,一直在CPU上运行,违背了“让权等待”
在这里插入图片描述

(二)硬件实现方法

1.中断屏蔽方法
当一个进程正在使用处理机执行它的临界区代码时,防止其他进程进入其临界区进行访问的最简方法是,禁止一切中断发生,或称为屏蔽中断、关中断。

即:关中断;临界区;开中断。关中断后不允许当前进程被中断,也不会发生进程切换。直到当前进程访问完临界区,再执行开中断指令,才有可能有别的进程上处理机并访问临界区

优点:简单、高效
缺点:不适用于多处理机(关中断是针对指定处理机的,对其他处理机不受影响,可能出现两个处理机上的两个进程同时访问处理机);只适用于操作系统内核进程,不适用于用户进程(因为开/关中断指令只能运行在内核态,这组指令如果能让用户随意使用会很危险)

2.硬件指令方法
(1)TestAndSet指令/TS/TSL指令:读出指定的标志后把该标志设置为真。这条指令是原子操作,即执行该代码时不允许被中断。

若初始lock为true,则old返回仍为true,while一直循环。

当前访问临界区的进程退出临界区,将lock改为false,下一个进程才能跳出while循环

违背“让权等待”
在这里插入图片描述

(2)Swap指令/XCHG指令:交换两个字(字节)的内容

违背“让权等待”

在这里插入图片描述

三.互斥锁

进程时间片用完才下处理机,违背“让权等待”

解决临界区最简单的工具就是互斥锁。一个进程在进入临界区时应获得锁;在退出临界区时释放锁。函数acquire()获得锁,而函数release()释放锁。每个互斥锁有一个布尔变量available,表示锁是否可用。如果锁是可用的,调用acqiure()会成功,且锁不再可用。当一个进程试图获取不可用的锁时,会被阻塞,直到锁被释放。

需要连续循环忙等的互斥锁,都可称为自旋锁,如TSL指令、swap指令、单标志法

优点:等待期间不用切换进程上下文,多处理器系统中,若上锁的时间短,则等待代价很低

在这里插入图片描述
常用于多处理器系统,一个核忙等,其他核照常工作,并快速释放临界区。不太适用于单处理机系统,忙等的过程中不可能解锁。

四.信号量机制

信号量机制可用来解决互斥与同步问题,它只能被两个标准的原语wait(S)和signal(S),也可记为“P操作”和“V操作”。

1.整型信号量
违背“让权等待”

wait(S) {
	while (S <= 0);
	S = S - 1;
}
signal(S) {
	S = S + 1;
}

2.记录型信号量

满足“让权等待”

typedef struct {
	int value;//剩余资源数
	struct process *L;//等待队列L
}semaphore;

当S.value<0时,S.value的绝对值表示等待进程个数

void wait(semaphore S) {//请求一个资源
	S.value--;
	if (S.value < 0) {
		add this process to S.L;//插入该类资源的等待队列S.L
		block(S.L);//自我阻塞,放弃处理机
	}
}
void signal(semahore S) {//释放一个资源
	S.value++;
	if (S.value <= 0) {
		remove a process P from S.L;//从该类资源的等待队列S.L上移除,进入就绪队列
		wakeup(P);//将S.L中的第一个等待进程唤醒
	}
}

3.利用信号量实现进程同步

语句x执行后y才能执行

semaphore S = 0;
P1() {
	x;
	V(S);
}
P2() {
	P(S);
	y;
}

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

临界资源的互斥访问

semaphore S = 1;
P1() {
	P(S);
	进程P1的临界区;
	V(S);
}
P2() {
	P(S);
	进程P2的临界区;
	V(S);
}

5.利用信号量实现前驱关系
要为每一对前驱关系各设置一个同步信号量,在“前操作”之后对相应的同步信号量执行V操作,在“后操作”之前对相应的同步信号量执行P操作(前V后P)

在这里插入图片描述
在这里插入图片描述

五.经典同步问题

(一)生产者-消费者问题

生产者和消费者对缓冲区互斥访问,生产者生产之后消费者才能消费。

1.基本问题

semaphore mutex = 1;
semaphore empty = n;
semaphore full = 0;
producer() {
	while (1) {
		produce an item in nextp;//生产数据
		P(empty);//获取空缓冲区单元

		P(mutex);//进入临界区
		add nextp to buffer;//将数据放入缓冲区
		V(mutex);//离开临界区,释放互斥信号量

		V(full);//满缓冲区数加1
	}
}
consumer() {
	while (1) {
		P(full);//获取满缓冲区单元
		
		P(mutex);
		remove an item from buffer;//从缓冲区取出数据
		V(mutex);

		V(empty);//空缓冲区数加1
		consume the item;//消费数据
	}
}

2.复杂问题
本例中对盘子的互斥访问无需设置mutex信号量
在这里插入图片描述

semaphore plate = 1, apple = 0, orange = 0;
dad() {
	while (1) {
		prepare an apple;
		P(plate);
		put the apple on the plate;
		V(apple);
	}
}
mom() {
	while (1) {
		prepare an orange;
		P(plate);
		put the orange on the plate;
		V(orange);
	}
}
son() {
	while (1) {
		P(orange);
		take an orange from the plate;
		V(plate);
		eat the orange;
	}
}
daughter() {
	while (1) {
		P(apple);
		take an apple from the plate;
		V(plate);
		eat the apple;
	}
}

(二)读者-写者问题

有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。

int conut = 0;//读者数量
semaphore mutex = 1;
semaphore rw = 1;//保证读者和写者互斥地访问文件
writer() {
	while (1) {
		P(rw);
		writing;
		V(rw);
	}
}
reader() {
	while (1) {
		P(mutex);//对count互斥访问
		if (count == 0)
			P(rw);//第一个读者来的时候rw减一即可(只有第一个读者需要加锁)
		count++;//读者计数器加1
		V(mutex);
		
		reading;//读取
		
		P(mutex);//对count互斥访问
		count--;//读者退出
		if (count == 0)
			V(rw);//最后一个读者退出,rw加1
		V(mutex);
	}
}

在上面算法中,读进程优先,会使得写操作被延迟。若有源源不断的读进程,会导致写进程饿死

代码改为

int conut = 0;//读者数量
semaphore mutex = 1;
semaphore rw = 1;
semaphore w = 1;
writer() {
	while (1) {
		P(w);//新增
		P(rw);
		writing;
		V(rw);
		V(w);//新增
	}
}
reader() {
	while (1) {
		P(w);//② 写进程执行P(w)后下一个读进程将被卡住,防止写进程饿死
		P(mutex);
		if (count == 0)
			P(rw);
		count++;
		V(mutex);
		V(w);//① w+1后,写进程即可执行P(w),卡在P(rw)

		reading;

		P(mutex);
		count--;
		if (count == 0)
			V(rw);
		V(mutex);
	}
}

(三)哲学家进餐问题

一张圆桌边上坐着5名哲学家,每两名哲学家之间的桌上摆一根筷子,两根筷子中间是一碗米饭。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。若筷子已在他人手上,则需要等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,进餐完毕后,放下筷子继续思考。
在这里插入图片描述

semaphore chopstick[5] = { 1,1,1,1,1 };
semaphore mutex = 1;
Pi() {
	do {
		P(mutex);//若同时拿起左边筷子,会造成死锁,所以要求至少有一人在左右筷子均可拿起时才动手
		P(chopstick[i]);//取左边筷子
		P(chopstick[(i + 1) % 5]);//取右边筷子
		V(mutex);
		eat;
		V(chopstick[i]);//放回左边筷子
		V(chopstick[(i + 1) % 5]);//放回右边筷子
		think;
	} while (1);
}

(四)吸烟者问题

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌上,如此重复(让三个抽烟者轮流地抽烟)。

int num = 0;
semaphore offer1 = 0;//烟草和纸的组合
semaphore offer2 = 0;//烟草和胶水的组合
semaphore offer3 = 0;//纸和胶水的组合
semaphore finish = 0;
process P1() {//供应者
	while (1) {
		num++;
		num = num % 3;
		if (num == 0)
			V(offer1);
		else if (num == 1)
			V(offer2);
		else
			V(offer3);
		任意两种材料放在桌子上;
		P(finish);
	}
}
process P2() {
	while (1) {
		P(offer3);
		拿纸和胶水,卷成烟,抽掉;
		V(finish);
	}
}
process P3() {
	while (1) {
		P(offer2);
		拿烟草和胶水,卷成烟,抽掉;
		V(finish);
	}
}
process P4() {
	while (1) {
		P(offer1);
		拿烟草和纸,卷成烟,抽掉;
		V(finish);
	}
}

六.管程

管程是代表共享资源的数据结构,以及由对该共享数据结构实时操作的一组过程所组成的资源管理程序。

管程的特性保证了进程互斥,无须程序员自己实现互斥,从而降低了死锁发生的可能性。同时管程提供了条件变量,可以让程序员灵活地实现进程同步。

管程由四部分组成:
①管程的名称
②局部于管程内部的共享结构数据说明(如:缓冲区)
③对该数据结构进程操作的一组过程(或函数)
④对局部于管程内部的共享数据设置初始值的语句

管程的引入是为了解决临界区分散所带来的管理和控制问题。在没有管程之前,对临界区的访问分散在各个进程之中,不易发现和纠正分散在用户程序中不正确使用P、V操作等问题。管程将这些分散在各进程中的临界区集中起来,并加以控制和管理,管程一次只允许一个进程进入管程内,从而既便于系统管理共享资源,又能保证互斥。

1.用管程解决生产者消费者问题
(1)需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
(2)需要在管程中定义用于访问这些共享数据的“入口”(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
(3)只有通过这些特定的“入口”才能访问共享数据
(4)管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证一个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的,程序员不用关心)
(5)可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”);可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。

在这里插入图片描述
2.Java中类似于管程的机制
Java中,如果用关键字synchronized来描述一个函数,那么这个函数同一时间段内只能被一个线程调用。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

流逝的一年

昨天远方的大哥打来了电话&#xff0c;我们聊了下近况。当他问及去年是否有新的著作问世&#xff0c;我不禁有些赧然&#xff0c;解释说还在学习中… 放下电话后&#xff0c;我陷入了思索&#xff1a;又是一年划上了句号&#xff0c;这一年我做了什么&#xff1f;我又有什么收…

数据库的一些基本概念

一、服务器&#xff1a;&#xff08;更正大家头脑中的一个错误认识&#xff09; 1、服务器是一种软件&#xff0c;不是硬件&#xff0c;不是计算机。 2、不同服务器负责调用不同类型的文件。 二、表文件、数据库、数据库服务器以及SQL语句&#xff1a; 1、表文件: …

一条 select 语句的执行过程

MySQL 从大方向来说&#xff0c;可以分为 Server 层和存储引擎层。而 Server 层包括连接器、查询缓存、解析器、预处理器、优化器、执行器等&#xff0c;最后 Server 层再通过 API 接口形式调用对应的存储引擎层提供的接口来执行增删改查操作。 如下即为一个简略的 select 语句…

Android动态运行时权限

android 6.0(API 级别 23)开始&#xff0c;android引入了运行时权限&#xff0c;应用安装时不向其授予权限&#xff0c;应用运行时向其授予权限。如果在运行时该功能没有动态地申请相应的权限&#xff0c;就会抛出SecurityException异常。 android的运行时权限的申请过程主要有…

C语言画一个正方体

程序截图 操作方法 鼠标拖动。左键拖动及滚轮能看到不同角度下正方体的形状&#xff0c;右键拖动能将最近的正方体顶点挪到这个投影面的相应位置。 按键控制。wasd 控制投影面旋转&#xff0c;ws 关于 x 轴旋转&#xff0c;ad 关于 y 轴旋转。 个人思路 首先投影面的确立需…

【寒假第一天】LeetCode刷题

&#x1f308;一.选择题&#x1f47f;1.1.堆是一种有用的数据结构。下列那个关键码序列是一个堆&#xff08; &#xff09;。 A. 94,31,53,23,16,72 B. 94,53,31,72,16,23 C. 16,53,23,94,31,72 D. 16,31,23,94,53,72D堆排序有两种排序方法&#xff1a;大堆排序-----根结点要大…

【Kotlin】Kotlin 函数总结 ( 具名函数 | 匿名函数 | Lambda 表达式 | 闭包 | 内联函数 | 函数引用 )

文章目录一、函数头声明二、函数参数1、默认参数值2、具名参数三、Unit 函数四、TODO 函数抛出异常返回 Nothing 类型五、反引号函数名六、匿名函数七、匿名函数的函数类型八、匿名函数的隐式返回九、匿名函数参数十、匿名函数 it 关键字十一、匿名函数变量类型推断十二、匿名函…

JS中BOM 浏览器对象 提供的定时器

window对象提供了2个定时器方法&#xff1a; settTimeout()和setInterval() 1.setTimeout()定时器 语法&#xff1a; window.setTimeout(调用函数,[延迟的毫秒数]);延迟时间可以省略&#xff0c;省略则为0 用于设置一个定时器&#xff0c;该定时器再定时器到期后执行调用函数 …

【nodejs】npm与包

1、什么是包 Node.js中的第三方模块又叫包 2、包的来源 由第三方个人或团队开发出来的&#xff0c;免费供所有人使用 3、为什么需要包 由于Node.js的内置模块仅提供了一些底层的API&#xff0c;导致在基于内置模块进行项目开发时&#xff0c;效率很低。 包是基于内置模块封装出…

杨校老师课堂之IntellJ IDEA的使用技巧

下载地址&#xff1a; https://www.jetbrains.com.cn/idea/download/#sectionwindows 一、常规操作 1、忽略大小写&#xff0c;进行提示 2、启用Idea时&#xff0c;默认不再打开上次项目 3、设置主题 4、设置默认的字体 5、修改类头的文档注释信息 6、设置项目文件编码 7、统一…

electron与jquery起冲突,使用jquery报错解决方法

问题原因&#xff1a;Electron 为了整合 Node.js&#xff0c;会在 DOM 加入 module、exports、require 等模块和函数&#xff0c;和jQuery、RequireJS、Meteor、AngularJS 等发生冲突。 暴力解决方法&#xff1a;去除node功能加持&#xff0c;在加载browserWindow或者browserVi…

C++:闭包:闭包Closure理解

一&#xff1a;什么是闭包 闭包有很多定义&#xff0c;一种说法是&#xff1a;闭包是带有上下文的函数&#xff0c;说白了&#xff0c;就是有状态的函数&#xff0c;这其实就是一个类&#xff0c;换个名字而已。 一个函数&#xff0c;带上一个状态&#xff0c;就变成了闭包&…

共享模型之管程(四)

1.wait/notify 1.1.为什么需要wait? 小故事: ①.假设多个用户(线程)都需要进入房间使用算盘(CPU)进行计算工作,但是为了保证计算过程中的安全,老王设计了一把锁(Synchronized),每次只允许一个用户(线程)拿到钥匙进入房间(成为Owner线程); ②.小南(线程)费了九牛二虎之力,抢…

【Docker】搭建Zookeeper集群

【Docker】搭建Zookeeper集群 下载镜像 docker pull zookeeper:3.5.8wy:study wy$ docker pull zookeeper:3.5.8 3.5.8: Pulling from library/zookeeperDigest: sha256:12af523731cbe390f5332d6c1e254f1d56c734a786910d5582653445a5cee299 Status: Downloaded newer image f…

Allegro174版本新功能介绍之动态铜皮对单独层面参数设置

Allegro174版本新功能介绍之动态铜皮对单独层面参数设置 Allegro升级到了174版本的时候,可以支持动态铜皮对单独的层面进行参数设置,如下图 具体操作如下 在低版本166以及172的时候,只有Global Dynamic Shape Parameter设置,如下图,只有全局的铜皮参数设置升级到了174时候…

WMS智能仓储管理系统源码 SpringMVC物流仓库管理系统源码

淘源码&#xff1a;国内知名的源码免费下载平台 需要源码学习可私信我。 系统介绍&#xff1a; 基于SpringMVCHibernatMinidao&#xff08;类Mybatis&#xff09;Easyui&#xff08;UI库&#xff09; Jquery Boostrap Ehcache Redis Ztree等基础架构开发的物流仓库管理系…

人脸识别:我是如何工作的?

任何自动人脸识别过程都必须考虑导致其复杂性的几个因素&#xff0c;因为人脸是一个动态实体&#xff0c;在多个因素的影响下不断变化&#xff0c;例如光照、姿势、年龄……这三个参数中的任何一个的变化都会导致同一个人的两幅图像之间的误差值大于不同个体的两幅图像之间的误…

分享136个PHP源码,总有一款适合您

PHP源码 分享136个PHP源码&#xff0c;总有一款适合您 136个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1A5sR357dh_SlS7pu33lW1Q?pwdkzgn 提取码&#xff1a;kzgn import os# 查找指定文件夹下所有相同名称的文件 def search_file(dirPath, fileName):dirs os…

红中私教-文件上传漏洞DVWA靶场实战(浅析)

前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红中 首先呢&#xff0c;针对于文件上传漏洞 这个漏洞为什么存在&#xff1f;目的是什么&#xff1f;我们为什幺要攻击…

开发环境和测试环境共用Eureka

问题描述 在开发过程中会遇到一种情况&#xff0c;那就是只需要修改一个服务&#xff0c;但是这个服务依赖了其他的3个服务&#xff0c;导致开发人员在本地也要启动其他的3个服务&#xff0c;还要启动一个Eureka注册中心。问题显而易见&#xff0c;在依赖过多的情况下&#xf…