理解线程/进程的死锁概念和如何解决死锁
在 windows 环境下,利用高级语言编程环境(限定为 VS 环境或 VC 环境)调用 CreateThread 函数哲学家就餐问题的演示。
要求:
(1)提供死锁的解法和非死锁的解法;
(2)有图形界面直观显示哲学家取筷子,吃饭,放筷子,思考等状态。
(3)为增强结果的随机性,各个状态之间的维持时间采用随机时间,例如100ms-500ms 之间。
用C语言编程
思路如下图所示:
首先,需要解决的是在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]);
}