一、实验目的
1、了解进程互斥、同步及其程序实现;
2、了解进程通信,以及利用进程互斥实现进程通信。
二、实验内容
Linux 上,用 C 语言信号量实现进程对临界资源的互斥访问
1、 信号量机制的基本操作:
资源使用者在使用临界资源之前“等待”信号量
资源使用者使用完临界资源后“通知”信号量
2、C 语言实现:
注意:以下函数原形在 sys/types.h、sys/ipc.h 和 sys/sem.h 包含文件中。
A)创建信号量集
int semget(key_t key,int nsems,int semfllg)
其中:key—创建信号量集关键字。
nsems—信号量集中信号量的数量。
semflg—指定选项及其权限位。
IPC_CREAT—创建新的信号量集
IPC_EXCEL—如果信号量集已经存在,则返回错误。
--和文件、目录一样权限。
返回一个信号量集 ID--semid
B) 获得一个已经存在的信号量集
int
semget(key_t key,0,0)
key—含义同上。
C)等待、通知一个信号量集
int semop(int semid,struct sembuf *sops,unsigned nsops)
semid—由函数 semget()产生的。
sops—描述信号量的操作:等待、通知等
struct
sembuf{
short sem_num;/*semaphore number */
short sem_op;
/*semaphore operation:-1 for waiting*/
short sem_flg;
/* operation flag :0、IPC_NOWAIT */
}
nsops—指定信号量集中操作的信号量个数。
D)
控制信号量集的操作
int semctl(int semid,int semnum,int cmd,union semun arg)
semid—由 semget()创建的信号量集标识。
semnum—信号量数量。
cmd—对信号量 semid 所进行的操作:SETALL—所有参数。
arg—对信号量集操作的初始数据。
arg 的类型:
union semun{
int
val; /* 仅用于参数 SETVAL*/
struct semid_ds *buf;
/*指向 IPC_STAT 和 IPC_SET 的 semid_ds 结构
ushort *array;
/*用于 GETALL 和 SETALL:指向一个初值的数
*/
*/
};
union semun arg;
本参数主要用于存放各个信号量的初始值。
三、实验要求
用三种方法解决 5 个哲学家进餐的问题(利用 fork()创建 5 个子进程,模拟五个哲学家.可
参照课间列出的三种方法和实验指导实验六中的参考代码.)
四、实验步骤
方法一:Sy41.c:
#include
#include
#include
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
}arg;
int semid;
philosopher(int i){
struct sembuf sbuf[2];
sbuf[0].sem_num=i;
sbuf[0].sem_flg=SEM_UNDO;
sbuf[1].sem_num=(i+1)%5;
sbuf[1].sem_flg=SEM_UNDO;
while(1){
printf("philosopher %d is thinking\n",i);
sleep(2);
printf("philosopher %d is hungry\n",i);
sbuf[0].sem_op=-1;
sbuf[1].sem_op=-1;
semop(semid,sbuf,2);
printf("philosopher %d is eating\n",i);
sleep(2);
sbuf[0].sem_op=1;
sbuf[1].sem_op=1;
semop(semid,sbuf,2);
}
}
main()
{
int semid,key,pid,status,i;
key=ftok("fname",1);
semid=semget(key,5,IPC_CREAT|0666);
arg.val=1;
for(i=0;i<5;i++){
semctl(semid,i,SETVAL,arg);
}
for(i=0;i<5;i++){
pid=fork();
if(pid==0){
philosopher(i);
}
}
pid=wait(&status);
}
方法二:Sy43.c:
#include
#include
#include
#include
#include
#include
//筷子作为 mutex
pthread_mutex_t chopstick[6] ;
void *eat_think(void *arg)
{
char phi = *(char *)arg;
int left,right; //左右筷子的编号
switch (phi){
case 'A':
left = 5;
right = 1;
break;
case 'B':
left = 1;
right = 2;
break;
case 'C':
left = 2;
right = 3;
break;
case 'D':
left = 3;
right = 4;
break;
case 'E':
left = 4;
right = 5;
break;
}
int i;
for(;;){
sleep(3); //思考
pthread_mutex_lock(&chopstick[left]); //拿起左手的筷子
printf("Philosopher %c fetches chopstick %d\n", phi, left);
if (pthread_mutex_trylock(&chopstick[right]) == EBUSY){ //拿起右手的筷子
pthread_mutex_unlock(&chopstick[left]); //如果右边筷子被拿走放下左手的筷
子
continue;
}
//
pthread_mutex_lock(&chopstick[right]); //拿起右手的筷子,如果想观察死锁,把上
一句 if 注释掉,再把这一句的注释去掉
printf("Philosopher %c fetches chopstick %d\n", phi, right);
printf("Philosopher %c is eating.\n",phi);
sleep(3); //吃饭
pthread_mutex_unlock(&chopstick[left]); //放下左手的筷子
printf("Philosopher %c release chopstick %d\n", phi, left);
pthread_mutex_unlock(&chopstick[right]); //放下左手的筷子
printf("Philosopher %c release chopstick %d\n", phi, right);
}
}
int main(){
pthread_t A,B,C,D,E; //5 个哲学家
int i;
for (i = 0; i < 5; i++)
pthread_mutex_init(&chopstick[i],NULL);
pthread_create(&A,NULL, eat_think, "A");
pthread_create(&B,NULL, eat_think, "B");
pthread_create(&C,NULL, eat_think, "C");
pthread_create(&D,NULL, eat_think, "D");
pthread_create(&E,NULL, eat_think, "E");
pthread_join(A,NULL);
pthread_join(B,NULL);
pthread_join(C,NULL);
pthread_join(D,NULL);
pthread_join(E,NULL);
return 0;
}
方法三:Sy45.c:
#include
#include
#include
#include
#include
#define phi_num 5
#define think_time 2
#define eat_time 1
#define left (phi_id+phi_num-1)%phi_num
#define right (phi_id+1)%phi_num
enum { think , hungry , eat } phi_state[phi_num];
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t state[phi_num]={PTHREAD_MUTEX_INITIALIZER};
void Do_think(int phi_id){
printf(" philosopher %d is thinking now !\n",phi_id);
sleep(think_time);
}
void Do_eat(int phi_id){
printf("philosopher %d is eating now !\n",phi_id);
sleep(eat_time);
}
void check_phi_state(int phi_id){
if(phi_state[phi_id]==hungry&&phi_state[left]!=eat&&phi_state[right]!=eat){
phi_state[phi_id]=eat;
pthread_mutex_unlock(&state[phi_id]);
}
}
void Do_take_forks(int phi_id){
pthread_mutex_lock(&mutex);
phi_state[phi_id]=hungry;
check_phi_state(phi_id);
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&state[phi_id]);
}
void Do_put_forks(int phi_id){
pthread_mutex_lock(&mutex);
phi_state[phi_id]=think;
check_phi_state(left);
check_phi_state(right);
pthread_mutex_unlock(&mutex);
}
void *philosopher(void *arg){
int phi_id=*(int *)arg;
while(1){
Do_think(phi_id);
Do_take_forks(phi_id);
Do_eat(phi_id);
Do_put_forks(phi_id);
}
return NULL;
}
int main(int argc, char *argv[]){
int num;
pthread_t *phi=(pthread_t*)malloc(sizeof(pthread_t)*phi_num);
int *id=(int *)malloc(sizeof(int)*phi_num);
for(num=0;num