操原上机(三) 哲学家就餐问题的死锁与非死锁解法

实验目的

理解线程/进程的死锁概念和如何解决死锁

实验内容

在 windows 环境下,利用高级语言编程环境(限定为 VS 环境或 VC 环境)调用 CreateThread 函数哲学家就餐问题的演示。
要求:
(1)提供死锁的解法和非死锁的解法;
(2)有图形界面直观显示哲学家取筷子,吃饭,放筷子,思考等状态。
(3)为增强结果的随机性,各个状态之间的维持时间采用随机时间,例如100ms-500ms 之间。

实验过程

用C语言编程
思路如下图所示:
操原上机(三) 哲学家就餐问题的死锁与非死锁解法_第1张图片
首先,需要解决的是在windows环境下实现p操作和v操作,这一点在之前的实验中已经模拟过了,因此不再介绍,直接上代码:

//创建5个信号量
for(int i=0;i<5;i++){
	S[i] = CreateSemaphore(NULL ,1 ,1,name[i]);
}
//打开信号量:
HANDLE right,left;
left =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[id]);
right=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[(id+4)%5]);
WaitForSingleObject(left,INFINITE);	//p操作
ReleaseSemaphore(left,1,NULL);	//v操作

完成p v操作之后,就可以按照上图中的伪代码进行程序的编写了。代码如下:

#include 
#include 
#include 

int i = 0; 
char name[5][2]={"0","1","2","3","4"};
int a[5]={1,1,1,1,1};
int random(void){
	int a=time (NULL);
	srand(a);
	return (rand()%400+100);
}
//子线程函数  
DWORD WINAPI philosopher(LPVOID lpParam){
	int id = i++;
	int time;
	HANDLE right,left;
	left =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[id]);
	right=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[(id+4)%5]);
	while(1){
		time = random();
		printf("哲学家%d开始思考,将思考%dms\n",id,time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dms\n",id,time);
		Sleep(time);
		//p(left)
		WaitForSingleObject(left,INFINITE); 
		printf("哲学家%d取了左手边的筷子\t%d\n",id,id);
		//p(right)
		WaitForSingleObject(right,INFINITE); 
		printf("哲学家%d取了右手边的筷子\t%d\n",id,(id+4)%5);
		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dms\n",id,time);
		Sleep(time);
		//v
		ReleaseSemaphore(left,1,NULL);
		printf("哲学家%d放下左手边的筷子\t%d\n",id,id);
		ReleaseSemaphore(right,1,NULL);
		printf("哲学家%d放下右手边的筷子\t%d\n",id,(id+4)%5);
	}
}
int main(void){
	HANDLE S[5];
	HANDLE hThread[5];
	for(int i=0;i<5;i++){
		S[i] = CreateSemaphore(NULL ,1 ,1,name[i]);
	}
	
	for(int i=0;i<5;i++){
		hThread[i] = CreateThread(NULL,0,philosopher,NULL,0,NULL);
	} 
	WaitForMultipleObjects(5,hThread,TRUE,10000); 	//等待子线程运行 
	for(int i=0;i<5;i++){
		CloseHandle(S[i]); 
	}
}

如果要避免死锁,只需要破坏死锁条件就可以了。这里我们可以采用有序资源分配方法来破坏环路条件,从而避免死锁。具体做法为将第0个哲学家的左筷子编号与右筷子编号互换,这样每一个哲学家的左筷子编号都比右筷子编号大,都会先请求编号大的资源,请求到之后再请求编号小的资源,从而不可能出现每一个哲学家都占有一个资源的情况出现。因此我们只需对原来的代码稍做以下修改即可:

HANDLE right,left;
if(id==0){
	right =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[id]);
	left=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[(id+4)%5]);
}
else{
	left =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[id]);
	right=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[(id+4)%5]);
}

你可能感兴趣的:(操作系统原理)