educoder平台
第二关哲学家就餐问题
书本上实例代码
//记录型信号量解决
semaphore chopstick[5]={1,1,1,1,1};//五根筷子信号量
do{
wait(chopstick[i]);//拿起第一根筷子
wait(chopstick([i+1)%5]);//拿起第二根筷子
//eat,持有两根筷子,就餐时间
signal(chopstick[i]);//放下第一根筷子
signal(chopstick([i+1)%5]);//放下第二根筷子
//第一位哲学家就餐完成,一直持续下去
}while(TRUE);
//and信号量机制解决
semaphore chopstick[5]={1,1,1,1,1};//五根筷子信号量
do{
...think
Swait(chopstick[i],chopstick([i+1)%5]);//同时拥有两根筷子
//eat,持有两根筷子,就餐时间
Ssignal(chopstick[i],chopstick([i+1)%5]);//放下筷子
//第一位哲学家就餐完成,一直持续下去
}while(TRUE);
//哲学家进餐问题
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
static sem_t sem_chops[5];//筷子信号量
static sem_t sem_stop;//该信号量用于等待。
//时间递增方法
void time_add_ms(struct timeval *time, uint ms)
{
time->tv_usec += ms * 1000; // 微秒 = 毫秒 * 1000
if(time->tv_usec >= 1000000) // 进位,1000 000 微秒 = 1 秒
{
time->tv_sec += time->tv_usec / 1000000;
time->tv_usec %= 1000000;
}
}
//100毫秒
#define TIMEOUT_FIRST 100
//200毫秒
#define TIMEOUT_HOLD 200
//200毫秒
#define TIMEOUT_PHIEND 200
//200毫秒
#define TIME_REPORT 200
struct timeval begintime; //获取的机器初始开始时间值
struct timespec first_time; //首次获取筷子信号量
struct timespec phi_holdtime; //保持一段时间
struct timespec report_time; //汇报线程完成情况时间
struct timespec phi_endtime; //哲学家线程结束绝对时间值
static int finish[5];
//哲学家线程没有进行有效同步控制
void* Philosopher(void *arg)
{
int iIndex=*((int*)arg);
int iRetWait1=-1,iRetWait2=-1;
//iRetWait1是获取筷子资源1的结果,成功返回0,失败返回-1
//iRetWait2是获取筷子资源2的结果,成功返回0,失败返回-1
iRetWait1=sem_timedwait(sem_chops+iIndex,&first_time);//获取筷子时间结果
/*begin ******哲学家线程获取筷子资源进餐*************************/
//获取第一个筷子成功后还要保持一段时间,继续请求下一个新筷子
sem_timedwait(&sem_stop,&phi_holdtime);
// 取第二个筷子,最多等待的时间点是700ms
iRetWait2=sem_timedwait(sem_chops+(iIndex+1)%5,&first_time);
if((iRetWait1==0)&&(iRetWait2==0))
{//检查获得两个筷子资源结果,都成功则为就餐成功
//设置任务完成标志为1,线程结束
finish[iIndex]=1;
//释放筷子资源iIndex
sem_post(&sem_chops[iIndex]);
//释放筷子资源
sem_post(&sem_chops[(iIndex+1)%5]);
}
/*end*********************************************/
//线程结束时间点:约为700MS
return;
}
//哲学家线程进行有效同步控制
void* PhilosopherGood(void *arg)
{
int iIndex=*((int*)arg);
int iRetWait1=-1,iRetWait2=-1;
int i=0;
/*begin ******哲学家线程获取筷子资源进餐-受同步控制*********************/
//根据线程编号选择筷子编号并尝试获取第一个筷子,未成功获取则等待一段时间后重试
//成功后继续请求下一个新筷子
for(i=0;(i<5)&&(iRetWait1!=0);i++){
//获取第一根筷子
if(iIndex%2==1){
iRetWait1=sem_timedwait(sem_chops+iIndex,&first_time);
}
iRetWait2=sem_timedwait(sem_chops+(iIndex+1)%5,&first_time);
//设置任务完成标志为1,线程结束
finish[iIndex]=1;
//释放筷子资源iIndex
sem_post(&sem_chops[iIndex]);
//释放筷子资源
sem_post(&sem_chops[(iIndex+1)%5]);
}
/****end*****************************************/
//线程结束时间点:约为700MS
return;
}
//该线程用于检测哲学家未经同步控制完成任务的数量
int ReporterPhi(void*(*phiFunc)(void*))
{
int iFinishCount=0;
pthread_t pids[5];
int arg[5];
int iRetWait1=-1,iRetWait2=-1,retVal=-1;
int i=0;
gettimeofday(&begintime, NULL);
//第一次获取筷子资源时间点:100MS
time_add_ms(&begintime, TIMEOUT_FIRST);
first_time.tv_sec = begintime.tv_sec;
first_time.tv_nsec = begintime.tv_usec * 1000;
//保持获取筷子资源到时间点:300MS
time_add_ms(&begintime, TIMEOUT_HOLD);
phi_holdtime.tv_sec = begintime.tv_sec;
phi_holdtime.tv_nsec = begintime.tv_usec * 1000;
//哲学家线程结束时间点:500毫秒
time_add_ms(&begintime, TIMEOUT_PHIEND);
phi_endtime.tv_sec= begintime.tv_sec;
phi_endtime.tv_nsec= begintime.tv_usec * 1000;
//汇报线程完成情况时间点:700MS
time_add_ms(&begintime, TIME_REPORT);
report_time.tv_sec = begintime.tv_sec;
report_time.tv_nsec = begintime.tv_usec * 1000;
sem_init(&sem_stop,0,0);//该信号量初值为0
//初始化完成数组为0,筷子信号量值为1
for(i=0;i<5;i++)
{
finish[i]=0;
//设置信量初值为1
sem_init(sem_chops+i,0,1);
}
for(i=0;i<5;i++)
{
arg[i]=i;//传给线程的参数值,用来区分线程实体
//创建消费者线程,pids+i是线程ID的保存地址,arg+i是线程的参数指针
pthread_create(pids+i,NULL,phiFunc,(void *)(&arg[i]));
}
//等待哲学家线程结束,但都没有完成任务。
for(i=0;i<5;i++)
{
pthread_join(pids[i],NULL); //主线程等待生产者线程结束
}
//等待到报告时间点:700MS
retVal = sem_timedwait(&sem_stop, &report_time);
iFinishCount=0;
for(i=0;i<5;i++)
{
if(finish[i]==1)
{iFinishCount++;}
}
return iFinishCount;
}
int main(int argc,char * argv[])
{
int i=0;
int phi1=-1,phi2=-1;
//调用无同步控制的哲学家线程
phi1=ReporterPhi(Philosopher);
//调用有同步控制的哲学家线程
phi2=ReporterPhi(PhilosopherGood);
//输出两种情况下完成任务的线程数
printf("%d,%d",phi1,phi2);
//销毁信号量资源
for(i=0;i<5;i++)
{
sem_destroy(sem_chops+i);
}
sem_destroy(&sem_stop);
return 0;
}