实验二 进程同步
一、实验目的:
掌握基本的同步算法,理解经典进程同步问题的本质;学习使用 Linux 的进程同步机制,
掌握相关 API 的使用方法;能利用信号量机制,采用多种同步算法实现不会发生死锁的哲
学家进餐程序。
二、实验平台:
虚拟机:VMware® Workstation 14 Pro 14.1.1
操作系统:Ubuntu
系统版本:Deepin 15.7
内核版本:4.15.0-29deepin-generic
编辑器: Vim 8.0.1766
编译器:Gcc 7.3.0
三、实验内容:
(1)以哲学家进餐模型为依据,在 Linux 控制台环境下创建 5 个进程,用 semget 函数
创建一个信号量集(5 个信号量,初值为 1),模拟哲学家的思考和进餐行为:每一位哲学家
饥饿时,先拿起左手筷子,再拿起右手筷子;筷子是临界资源,为每一支筷子定义 1 个互斥
信号量;想拿到筷子需要先对信号量做 P 操作,使用完释放筷子对信号量做 V 操作。
伪代码描述:
semaphore chopstick[5]={1,1,1,1,1};
第 i 位哲学家的活动可描述为:
do{
printf("%d is thinking\n",i);
printf("%d is hungry\n",i);
wait(chopstick[i]);
//拿左筷子
wait(chopstick[(i+1) % 5]);
//拿右筷子
printf("%d is eating\n",i);
signal(chopstick[i]);
signal(chopstick[(i+1) % 5]);
//放左筷子
//放右筷子
…
}while[true];
运行该组进程,观察进程是否能一直运行下去,若停滞则发生了什么现象?并分析原因。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef
union semun
{
_SEM_SEMUN_UNDEFINED
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int wait_1chopstick(int no,int semid)
{
struct sembuf sb = {no,-1,0};
int ret;
ret = semop(semid,&sb,1);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
int free_1chopstick(int no,int semid)
{
struct sembuf sb = {no,1,0};
int ret;
ret = semop(semid,&sb,1);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
#define DELAY (rand() % 5 + 1)
void wait_for_2chopstick(int no,int semid)
{
int left = no;
int right = (no + 1) % 5;
struct sembuf buf[2] = {
{left,-1,0},
{right,-1,0}
};
semop(semid,buf,2);
}
void free_2chopstick(int no,int semid)
{
int left = no;
int right = (no + 1) % 5;
struct sembuf buf[2] = {
{left,1,0},
{right,1,0}
};
semop(semid,buf,2);
}
void philosophere(int no,int semid)
{
srand(getpid());
for(;;) {
#if 0
printf("%d is thinking\n",no);
sleep(DELAY);
printf("%d is hungry\n",no);
wait_for_2chopstick(no,semid);
printf("%d is eating\n",no);
sleep(DELAY);
free_2chopstick(no,semid);
#else
int left = no;
int right = (no + 1) % 5;
printf("%d is thinking\n",no);
sleep(DELAY);
printf("%d is hungry\n",no);
wait_1chopstick(left,semid);
sleep(DELAY);
wait_1chopstick(right,semid);
printf("%d is eating\n",no);
sleep(DELAY);
free_1chopstick(left,semid);
free_1chopstick(right,semid);
#endif
}
}
int main(int argc,char *argv[])
{
int semid;
semid = semget(IPC_PRIVATE,5,IPC_CREAT | 0666);
if(semid < 0) {
ERR_EXIT("semid");
}
union semun su;
su.val = 1;
int i;
for(i = 0;i < 5;++i) {
semctl(semid,i,SETVAL,su);
}
int num = 0;
pid_t pid;
for(i = 1;i < 5;++i) {
pid = fork();
if(pid < 0) {
ERR_EXIT("fork");
}
if(0 == pid) {
num = i;
break;
}
}
philosophere(num,semid);
return 0;
}
执行结果
实验结果分析:
起初,实验结果一直如图一,会有 semop: Interrupted system call,后通过百度查明原
因 , 是 因 为 信 号 量 中 断 导 致 的 , 于 是 就 在 wait 操 作 上 做 了 些 修 改 , 把 ret =
semop(semid,&sb,1 改为 while(ret = semop(semid,&sb,1)&&errno==EINTR);即出现信号
量中断时循环运行,遂解决。
之后的结果如图二所示,出现死锁,具体原因应该是在每个哲学家思考拿了左筷子
之后有一个 sleep()函数使当前进程沉睡,系统调用下一个进程,直至五个哲学家一
人一只筷子,进程死锁。
(2)方法b代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int wait_1chopstick(int no,int semid)
{
_SEM_SEMUN_UNDEFINED
struct sembuf sb = {no,-1,0};
int ret;
while(ret = semop(semid,&sb,1)&&errno==EINTR);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
int waitchopstick(int semid)
{
struct sembuf sb = {5,-1,0};
int ret;
while(ret = semop(semid,&sb,1)&&errno==EINTR);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
int free_1chopstick(int no,int semid)
{
struct sembuf sb = {no,1,0};
int ret;
ret = semop(semid,&sb,1);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
int freechopstick(int semid)
{
struct sembuf sb = {5,1,0};
int ret;
ret = semop(semid,&sb,1);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
#define DELAY (rand() % 5 + 1)
void wait_for_2chopstick(int no,int semid)
{
int left = no;
int right = (no + 1) % 5;
struct sembuf buf[2] = {
{left,-1,0},
{right,-1,0}
};