程序结构设计
程序需要六个线程,主线程用于显示主菜单,接收用户的功能选择;五个哲学家线程用于模拟哲学家的活动,即不停地思考、饥饿、进食。相邻的两个哲学家线程需要共享他们中间的同一根筷子,因此对每一根筷子的使用要互斥,用互斥体数组h_mutex_chopsticks来实现。主线程创建五个哲学家线程后要等待所有哲学家结束,用线程句柄数组h_thread来表示五个线程,主线程通过等待这五个线程句柄来实现同步。
算法设计
下面给出主要函数的算法描述。
(1)deadlock_philosopher函数
{
while(1){
随机等待一段时间;
提示等待左边筷子;
申请左边筷子;
随机等待一段时间;
提示等待右边筷子;
申请右边筷子;
提示正在进餐;
放下左边筷子;
放下右边筷子;
}
}
(2)ordered_allocation_philosopher函数
{
while(1){
随机等待一段时间;
提示等待左右两边编号较小的筷子;
申请编号较小的筷子;
随机等待一段时间;
提示等待左右两边编号较大的筷子;
申请编号较大的筷子;
提示正在进餐;
放下编号较小的筷子;
放下编号较大的筷子;
}
}
(3)pre_allocation_philosopher函数
{
while(1){
提示等待左边筷子;
提示等待右边筷子;
同时申请左边和右边两根筷子;
提示正在进餐;
随机等待一段时间;
放下左边筷子;
放下右边筷子;
}
}
(4)deadlock函数
{
为每根筷子创建一个互斥信号量;
创建五个可能产生死锁的哲学家线程;
等待五个哲学家线程结束;
}
其他的初始化函数与deadlock()的算法相同,只不过在创建线程时使用不同的线程函数。
在windows中可以用系统调用WaitForMultipleObjects()同时申请两份资源,但是在linux中没有相应的系统调用,因此要在linux下实现资源预分配法,就要自己编写同时申请两根筷子的函数。这需要将哲学家的状态增至三个, 即思考、饥俄、进食,每个哲学家仅在饥俄时才申请筷子,而且同时申请其左右两根筷子,如果此时左右两根子不同时空闲,则哲学家将等待。具体解法如下所示。
#define N 5
typedef enum{
thinking, hungry, eating}status;
status state[N];
semaphore self[N];
semaphore mutex = 1;
void test(int i)
{
if((state[i] == hungry)&&
(state[(i-1)%N] != eating)&&
(state[(i+1)%N] != eating)){
state[i] = eating;
V(self[i]);
}
}
void pick_chopsticks(int i)
{
P(mutex);
state[i] = hungry;
test(i);
V(mutex);
P(self[i]);
}
void put_chopsticks(int i)
{
P(mutex);
state[i] = thinking;
test((i-1)%N);
test((i+1)%N);
V(mutex);
}
void philosopher(int i)
{
while(1){
think();
pick_chopsticks(i);
eat();
put_chopsticks(i);
}
void main
{
int i;
for(i=0;i<5;i++){
state[i] = thingking;
self[i].value = 0;
}
}
在上述程序中, 自定义数据类型status用来枚举哲学家的状态,数组state用来存放五个哲学家的状态,由于该数组是全局变量,所以用信号灯变量mutex实现对它的互斥访问。信号量数组self包含五个元素,每个元素的初始值皆为0,当第i号哲学家不具备进食条件时,会将自己阻塞在信号量self[i]上。函数test用于测试i号哲学家是否具备进食的条件。i号哲学家可以进食必须同时满足以下条件:i号哲学家饥饿,左边哲学家不在进食,右边哲学家不在进食。
【linux下的程序代码】
编译命令:
gcc dinning .c –o dinning.o –lcurses –lpthread
程序清单
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <curses.h>
#include <time.h>
#include <semaphore.h>
#include <string.h>
#define MAX_PHILOSOPHERS 5
#define ZERO 48
#define DELAY (rand()%25)/1000
typedef enum {
thinking,hungry,eating}status;//status用来枚举哲学家的状态
status state[MAX_PHILOSOPHERS];//存放五个哲学家的状态,全局变量
pthread_mutex_t pre_mutex;//用信号灯变量mutex实现对state的互斥访问
sem_t pre_self[MAX_PHILOSOPHERS];//信号量数组self包含五个元素,每个元素的初始值皆为0
pthread_mutex_t h_mutex_chopsticks[MAX_PHILOSOPHERS];//互斥体数组实现对每一根筷子的互斥使用
int thread_number[MAX_PHILOSOPHERS]=