⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 philosopher5.h

📁 改进的哲学家问题
💻 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 + -