📄 philosopher5.h
字号:
#include "ourhdr.h"
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
#define N 5
#define LEFT ((myID+N-1)%N)//逆时针坐着五位philosophers
#define RIGHT ((myID+N+1)%N)
struct PID
{
pid_t P[N];//用共享内存实现各进程的pid和philosopher的编号统一
};
struct PID PIDS;
struct PID *pids;
time_t local_time;
struct sigaction act_1,act_2;//sigaction函数的信号动作
union sigval val;/***typedef union sigval {
int sival_int;
void *sival_ptr;
};***/
struct Queue
{
int flag;/*flag=0当前无申请,flag=1有申请*/
int T;
};
/*管道处理*/
struct pipe_fd
{
int m_read;
int m_write;
};
struct Queue q[N];/*每个进程维护的消息队列*/
sigset_t mask,old_mask;/*只响应SIGRTMIN+1,SIGRTMIN+2信号。不可靠信号是信号值小于SIGRTMIN的信号*/
static char *shmptr;//共享存储ptr
static int shmid;
struct pipe_fd pipe_fds[N*N];//管道记录,N个进程两两通信(管道单向)
int receive[N];/*子进程中使用*/
char *time_buf;
/************************************************************************************************/
int myID;/*记住自己的编号*/
int in;/*in=0不在临界区,in=1正在临界区*/
int allow_L,allow_R;/*记录有多少reply*/
void initforks();
void sig_request(int,siginfo_t*,void*);
void sig_reply(int,siginfo_t*,void*);
void init_child();
/*******************************************************************************************/
void think(int i)
{
printf("Philosopher %d is thinking\n", i);
sleep(2);
}
void eat(int i)
{
printf("Philosopher %d is eating\n", i);
sleep(2);
}
void take_fork(int i)
{
int j;
val.sival_int = i;//要传递的参数进程编号
local_time++;
q[myID].T = local_time;
q[myID].flag = 1;//有申请
for(j=0;j<N;j++)
{
if(j==myID) continue;
write(pipe_fds[j*N+myID].m_write,&local_time,sizeof(local_time));
//在相应管道写入消息时间
sigqueue(pids->P[j],SIGRTMIN+1,val);//向进程j发送信号,参数在val中
}
while(in!=1);//in=1在临界区中
}
void put_fork(int i)
{
int j;
printf("%d philosopher put both left and right forks\n",myID);
val.sival_int = myID;
for(j=0;j<N;j++)
{
if(j==myID) continue;
if(q[j].flag==1)//进程j需要资源
{
q[j].flag = 0;//放弃资源
sigqueue(pids->P[j],SIGRTMIN+2,val);/*传递reply信息给进程j*/
}
}
in = 0;/*表示退出临界区*/
}
/********************************************************************************************/
void initforks()
{
int i;
int fd[2];
int key;
for(i=0;i<N*5;i++)
{
if(pipe(fd)<0)//创建管道,返回2个文件描述符 fd[0]读 fd[1]写
{
perror("pipe");
exit(1);
}
pipe_fds[i].m_read = fd[0];
pipe_fds[i].m_write = fd[1];
}/*初始化管道记录*/
if((time_buf = (char*)malloc(6))==NULL)
{
perror("malloc");
exit(1);
}
key = 998001;
if( (shmid = shmget( key, sizeof(PIDS), IPC_CREAT|0600)) != -1) //申请共享存储区
{
if( (shmptr = (char*)shmat(shmid,0,0)) == (char*)-1 )//连接到物理地址
{
perror("shmptr_parent_attach");
exit(1);
}
memcpy(shmptr,(char*)&PIDS,sizeof(PIDS));//复制存储区
/* 目的 源 大小*/
}
else
{
perror("shmid_parent_creation");
exit(2);
}
for(i=0;i<N;i++)
{
q[i].T = 0;/*Ti=0*/
q[i].flag = 0;/*当前无申请*/
}
sigemptyset(&mask);//mask的类型为sigset_t,这里使mask定义为全部信号均不被阻塞
sigaddset(&mask,SIGRTMIN+1);//增加相应的需要的信号
sigaddset(&mask,SIGRTMIN+2);
sigaddset(&mask,SIGINT);/*为^C留一出口*/
act_1.sa_sigaction = sig_request;//信号捕捉函数
act_2.sa_sigaction = sig_reply;
act_1.sa_mask = act_2.sa_mask = mask;//处理信号时能阻塞同类信号
//在调用信号捕捉函数前,该信号集要加到进程的信号屏蔽字中。返回时再次恢复
act_1.sa_flags = act_2.sa_flags = SA_SIGINFO;//为信号处理程序提供附加信息
//附加的2个参数被传给信号处理程序(int型的信号编号和siginfo_t型的参数)
if (sigaction(SIGRTMIN+1,&act_1,NULL)<0)
//signal函数,&act_1提供修改动作,SIGRTMIN+1为编号数33
err_sys("sigaction(SIGRTMIN+1) error");
if (sigaction(SIGRTMIN+2,&act_2,NULL)<0)
err_sys("sigaction(SIGRTMIN+2) error");
//request = 0;/***alive***/
in = 0;//非临界区
}
void sig_request(int signo,siginfo_t *info,void *myact)
{
int j,i;
time_t max;
j = (int)info->si_int;//发送者的编号POSIX.1b signal
read(receive[j],&max,sizeof(max));
//读本地时间。receive[j]为进程j的接收管道,见init_child()
local_time = ((max>local_time)?max:local_time)+1;//更新时间
q[j].T = max;
q[j].flag = 1;//申请,置申请标志
val.sival_int = myID;
if(in==1)/*若Pi正在临界区*/ ;
else if(q[myID].flag==0||(j!=LEFT&&j!=RIGHT))//无资源冲突
{
q[j].flag = 0;
sigqueue(pids->P[j],SIGRTMIN+2,val);/*传递reply信息给进程i*/
}
else if(q[myID].flag==1&&(q[j].T>q[myID].T||(q[j].T==q[myID].T&&j>myID)))
/*若Pi正在等待进入临界区但到达的消息在Pi请求之后,即myID申请在前*/ ;
else
{ /*若Pi正在等待进入临界区且到达的消息在Pi请求之前*/
q[j].flag = 0;
sigqueue(pids->P[j],SIGRTMIN+2,val);/*传递reply信息给进程i*/
}
printf("philosopher %d receive request from %d , time = %d\n",myID,j,max);
}
void sig_reply(int signo,siginfo_t *info,void *myact)
{
int j,max;
j = (int)info->si_int;
printf("%d receive reply from %d\n",myID,j);
if(j==LEFT) allow_L++;
if(j==RIGHT) allow_R++;
if(allow_L>0 && allow_R>0)//左右叉子均可待用
{
in = 1;/*表示进入临界区*/
allow_L=0;
allow_R=0;
q[myID].flag = 0;
}
}
void init_child()
{
int i;
for(i=0;i<N;i++)
{
close(pipe_fds[myID*N+i].m_write);/* 关闭对自己的写 */
receive[i] = pipe_fds[myID*N+i].m_read;/* 只能读自己的管道 */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -