操作系统软件实现互斥

操作系统软件实现临界区互斥

三种算法

单标志法

int turn = 0;           // 用turn来表示该临界区能够被谁访问,初始化随意,0或者1都行
void P0(){
    while(turn!=0);		// 如果turn!=0表示P0进程不能访问,则循环等待
    critical section;	// 到这步之后,即turn=0,进入临界区访问
    turn = 1;			// 用完之后,退出临界区,把使用权交给P1
    others;				// 其他的操作
}
void P1(){
    while(turn!=1);		// P1的执行顺序同P0
    critical section;
    turn = 0;
    others;
}
思路:
用一个整形变量来表示哪个进程能够访问临界资源,实现互斥访问,
同时访问完之后对turn的值进行更改,使得其他进程能够使用临界区资源,
turn可以想象成谦让方式,方便理解
缺点:
如果P0进程访问完之后,turn=1,但是P1不对临界区进行访问,turn的值就一直得不到改变,
即使临界区空闲,P0也不能进入临界区,造成资源利用不充分。

单标志法实现了临界区访问互斥,但未实现空闲让进和让权等待

双标志法

先检验
bool flag[2];     // 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
void P0(){
    while(flag[1]) ;		// 如果临界区现在没有被P1访问,则进入临界区,反之则等待
    flag[0] = true;			// P0进入临界区之后表明自己已经在使用临界区了,修改flag[0]的值为1
    critical section;		// 使用临界区
    flag[0] = false;		// 使用完临界区之后,让出使用权,修改flag[0]的值为0
    others;					// 其他的操作
}
void P1(){
    while(flag[0]) ;		// 同P0
    flag[1] = true;
    critical section;
    flag[1] = false;
    others;
}
思路:
因为单标志位用turn表示礼让,导致有可能临界区空闲但却不能使用的问题,所以双标志位为了解决这个问题,用一个flag数组表示当前进程是否在使用临界区,
在进程想使用临界区的时候查询是否有其他进程在使用临界区,
如果有则等待,如果没有则进入临界区,同时表明自己在使用临界区修改flag为1,使用完成后放弃临界区资源,修改flag为0,
flag可理解为占位的方式,方便理解
缺点:
因为进程是并发执行的,所以有可能在P0查询完flag[1]之后还未执行flag[0]=1之前,
处理器转去执行P1进程,P1也对flag[0]进行查询为0,也进入临界区,这样导致有两个进程进入临界区访问资源,
问题出现在进程进入临界区和修改flag为1的操作不能一次进行,有可能被中途截断,导致出错

为了解决单标志位的空闲让进问题,导致出现不能实现互斥访问临界区,即忙则等待原则,同时让权等待还是未能实现

后检验
bool flag[2];     // 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
void P0(){
    flag[0] = true;			// 对flag的赋值放在前面,表示自己想要使用临界区,先占下位置,防止先检查的问题出现
    while(flag[1]) ;		// 如果临界区现在没有被P1访问,则进入临界区,反之则等待
    critical section;		// 使用临界区
    flag[0] = false;		// 使用完临界区之后,让出使用权,修改flag[0]的值为0
    others;					// 其他的操作
}
void P1(){
    flag[1] = true;
    while(flag[0]) ;		// 同P0
    critical section;
    flag[1] = false;
    others;
}
思路:
为了解决双标志位先检查的错误,即有可能同时有多个进程进入临界区的问题,
后检查用先修改flag为1来表示占位,以防止这种问题的发生,其他的思想和双标志位法先检查类似
缺点:因为进程的并发进行,所以,当P0执行完flag=1后,
处理机转而去处理P1进程的flag=1,导致flag都等于1,双方都进不去,即使临界区空闲,

为了解决双标志位法先检查的忙则等待问题,导致出现空闲让进的问题,同时让权等待还是未能实现

Peterson’s Algorithm

bool flag[2];					// 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
int turn = 0;					// 用turn来表示该临界区能够被谁访问,初始化随意,0或者1都行
void P0(){
    flag[0] = true;				// 先表达我要使用临界区的意愿,占位,修改flag的值
    turn = 1;					// 表示P1可以使用这个临界区
    while(flag[1]&&turn==1) ;	// 当且仅当满足P1已经表明了使用临界区资源的意愿且P1能使用临界区的条件,则等待
    // 否则进入临界区,这里用flag发出了询问,如果P1没有想使用临界区的意愿,
    // 那么即使我把临界区的使用权给了P1我也能进入临界区,
    // 同时这样也不会导致锁死,因为如果P0不进去,P1必定能进去,
    // 因为P1已经表达了进去的意愿
    critical section;			//进入临界区
    flag[0] = false;			//退出,让出使用权
    others;
}
void P1(){						//同P0
    flag[1] = true;
    turn = 0;
    while(flag[0]&&turn==0) ;
    critical section;
    flag[1] = false;
    others;
}
思路:
汲取了单标志位和双标志位后检查法的优点,同时使用两个变量turn和flag来表示对临界区的访问次序,
用turn表谦让,用flag表意愿或者说占位(占位了即表示想使用),进入临界区的时候判断两个变量的值
用turn解决互斥访问,用flag解决饥饿问题
即使flag都为1,但是turn的值只能有一个,则必有一个进程能进入临界区,不会导致饿死的状态,
同时也只能有一个条件能满足,则只能有一个进程进入临界区
缺点:不能实现让权等待的问题

以下为总的代码,不能运行

#include <bits/stdc++.h>
using namespace std;
// 单标志法
class OneFlag(){
	int turn = 0;           // 用turn来表示该临界区能够被谁访问,初始化随意,0或者1都行
	void P0(){
		while(turn!=0);		// 如果turn!=0表示P0进程不能访问,则循环等待
		critical section;	// 到这步之后,即turn=0,进入临界区访问
		turn = 1;			// 用完之后,退出临界区,把使用权交给P1
		others;				// 其他的操作
	}
	void P1(){
		while(turn!=1);		// P1的执行顺序同P0
		critical section;
		turn = 0;
		others;
	}
	/*
		单标志位的
		思路:用一个整形变量来表示哪个进程能够访问临界资源,实现互斥访问,
			同时访问完之后对turn的值进行更改,使得其他进程能够使用临界区资源,
			turn可以想象成谦让方式,方便理解
		缺点:如果P0进程访问完之后,turn=1,但是P1不对临界区进行访问,turn的值就一直得不到改变,
			即使临界区空闲,P0也不能进入临界区,造成资源利用不充分。
		实现了临界区访问互斥,但未实现空闲让进和让权等待
	 */
};

// 双标志位法先检查
class TwoFlagFirst
{
	bool flag[2];     // 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
	void P0(){
		while(flag[1]) ;		// 如果临界区现在没有被P1访问,则进入临界区,反之则等待
		flag[0] = true;			// P0进入临界区之后表明自己已经在使用临界区了,修改flag[0]的值为1
		critical section;		// 使用临界区
		flag[0] = false;		// 使用完临界区之后,让出使用权,修改flag[0]的值为0
		others;					// 其他的操作
	}
	void P1(){
		while(flag[0]) ;		// 同P0
		flag[1] = true;
		critical section;
		flag[1] = false;
		others;
	}
	/*
		双标志位的
		思路:因为单标志位用turn表示礼让,导致有可能临界区空闲但却不能使用的问题,
			所以双标志位为了解决这个问题,用一个flag数组表示当前进程是否在使用临界区,
			在进程想使用临界区的时候查询是否有其他进程在使用临界区,如果有则等待,
			如果没有则进入临界区,同时表明自己在使用临界区修改flag为1,使用完成后放弃临界区资源,修改flag为0
			flag可理解为占位的方式,方便理解
		缺点:因为进程是并发执行的,所以有可能在P0查询完flag[1]之后还未执行flag[0]=1之前,
			处理器转去执行P1进程,P1也对flag[0]进行查询为0,也进入临界区,
			这样导致有两个进程进入临界区访问资源,
			问题出现在进程进入临界区和修改flag为1的操作不能一次进行,有可能被中途截断,导致出错
		为了解决单标志位的空闲让进问题,导致出现不能实现互斥访问临界区,即忙则等待原则,同时让权等待还是未能实现
	 */
};

// 双标志位法后检查
class TwoFlagSecond
{
	bool flag[2];     // 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
	void P0(){
		flag[0] = true;			// 对flag的赋值放在前面,表示自己想要使用临界区,先占下位置,防止先检查的问题出现
		while(flag[1]) ;		// 如果临界区现在没有被P1访问,则进入临界区,反之则等待
		critical section;		// 使用临界区
		flag[0] = false;		// 使用完临界区之后,让出使用权,修改flag[0]的值为0
		others;					// 其他的操作
	}
	void P1(){
		flag[1] = true;
		while(flag[0]) ;		// 同P0
		critical section;
		flag[1] = false;
		others;
	}
	/*
		双标志法后检查的
		思路:为了解决双标志位先检查的错误,即有可能同时有多个进程进入临界区的问题,
			后检查用先修改flag为1来表示占位,以防止这种问题的发生,其他的思想和双标志位法先检查类似
		缺点:因为进程的并发进行,所以,当P0执行完flag=1后,处理机转而去处理P1进程的flag=1,
			导致flag都等于1,双方都进不去,即使临界区空闲
		为了解决双标志位法先检查的忙则等待问题,导致出现空闲让进的问题,同时让权等待还是未能实现
		总结都是进程并发惹得毛病[狗头保命],其实是因为flag的修改和进入临界区的操作不能一次进行
	 */
};

// Peterson's Algorithm
class Peterson
{
	bool flag[2];					// 用flag数组来表示该临界区是否被另外一个进程访问,故初始值都为0
	int turn = 0;					// 用turn来表示该临界区能够被谁访问,初始化随意,0或者1都行
	void P0(){
		flag[0] = true;				// 先表达我要使用临界区的意愿,占位,修改flag的值
		turn = 1;					// 表示P1可以使用这个临界区
		while(flag[1]&&turn==1) ;	// 当且仅当满足P1已经表明了使用临界区资源的意愿且P1能使用临界区的条件,则等待
									// 否则进入临界区,这里用flag发出了询问,如果P1没有想使用临界区的意愿,
									// 那么即使我把临界区的使用权给了P1我也能进入临界区,
									// 同时这样也不会导致锁死,因为如果P0不进去,P1必定能进去,
									// 因为P1已经表达了进去的意愿
		critical section;			//进入临界区
		flag[0] = false;			//退出,让出使用权
		others;
	}
	void P1(){						//同P0
		flag[1] = true;
		turn = 0;
		while(flag[0]&&turn==0) ;
		critical section;
		flag[1] = false;
		others;
	}
	/*
		Peterson's Algorithm的:
		思路:汲取了单标志位和双标志位后检查法的优点,同时使用两个变量turn和flag来表示对临界区的访问次序
			用turn表谦让,用flag表意愿或者说占位(占位了即表示想使用),进入临界区的时候判断两个变量的值
			用turn解决互斥访问,用flag解决饥饿问题
			即使flag都为1,但是turn的值只能有一个,则必有一个进程能进入临界区,不会导致饿死的状态,
			同时也只能有一个条件能满足,则只能有一个进程进入临界区
		缺点:不能实现让权等待的问题
	 */
};

int main(){
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值