软件学院实验报告
实验题目:进程同步实验
1.实验目标:
加深对并发协作进程同步与互斥概念的理解,观察和体验并发进
程同步与互斥操作的效果,分析与研究经典进程同步与互斥问题的实
际解决方案。了解Linux系统中IPC进程同步工具的用法,练习并发协
作进程的同步与互斥操作的编程与调试技术。
2.实验环境
硬件环境: PC
软件环境:linux
4.源代码注释
1、生产者的代码如下:
#include "ipc.h"
int main(int argc,char *argv[]) {
int rate;
char *yl1[]={"烟草","纸","胶水"};
//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度
if(argv[1] != NULL)
rate = atoi(argv[1]);
else rate =3; //不指定为 3 秒
//共享内存使用的变量
buff_key = 101;//缓冲区任给的键值
buff_num = 2;//缓冲区任给的长度
pput_key = 102;//生产者放产品指针的键值
pput_num = 1; //指针数
shm_flg = IPC_CREAT | 0644;//共享内存读写权限
//获取缓冲区使用的共享内存,buff_ptr 指向缓冲区首地址
buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg);
//获取生产者放产品位置指针 pput_ptr
pput_ptr = (int *)set_shm(pput_key,pput_num,shm_flg);
//信号量使用的变量
prod_key = 203;//生产者同步信号灯键值
pmtx_key = 204;//生产者互斥信号灯键值
cons1_key = 307;//消费者 1 同步信号灯键值
cmtx1_key = 308;//消费者 1 互斥信号灯键值
cons2_key = 303;//消费者 2 同步信号灯键值
cmtx2_key = 304;//消费者 2 互斥信号灯键值
cons3_key = 305;//消费者 3 同步信号灯键值
cmtx3_key = 306;//消费者 3 互斥信号灯键值
sem_flg = IPC_CREAT | 0644;
//生产者同步信号灯初值设为缓冲区最大可用量
sem_val = 1;
//获取生产者与消费者同步信号灯,引用标识存 prod_sem
prod_sem = set_sem(prod_key,sem_val,sem_flg);
//消费者初始无产品可取,同步信号灯初值设为 0
sem_val = 0;
//获取消费者同步信号灯,引用标识存 cons_sem
cons1_sem = set_sem(cons1_key,sem_val,sem_flg);
cons2_sem = set_sem(cons2_key,sem_val,sem_flg);
cons3_sem = set_sem(cons3_key,sem_val,sem_flg);
//生产者互斥信号灯初值为 1
sem_val = 0;
//获取生产者同步信号灯,引用标识存 pmtx_sem
pmtx_sem = set_sem(pmtx_key,sem_val,sem_flg);
//循环执行模拟生产者不断放产品
int u=0;
while(1){
//如果缓冲区满则生产者阻塞
down(prod_sem);
sleep(rate);
int i=rand()%3+1;
*pput_ptr=0;
buff_ptr[*pput_ptr]=i;
printf("%d
producer
put:
%s
to
Buffer[%d]\n",getpid(),yl1[i-1],*pput_ptr);
up(pmtx_sem); //唤醒生产者 2
u=u+1;
}
return EXIT_SUCCESS;
}
生产者 2 与生产者 1 不同之处:
while(1){
//如果缓冲区满则生产者阻塞
//down(prod_sem);
//如果另一生产者正在放产品,本生产者阻塞
down(pmtx_sem);
*pput_ptr=0;
int j=buff_ptr[*pput_ptr];
int i=j%3+1;
*pput_ptr=1;
buff_ptr[*pput_ptr]=i;
if(i!=1&&j!=1){
//buff_ptr[*pput_ptr] = '1';
up(cons1_sem);
printf("%d
producer
put:
%s
to
Buffer[%d]\n",getpid(),yl2[i-1],*pput_ptr);
}
if(i!=2&&j!=2){
//buff_ptr[*pput_ptr] = '2';
up(cons2_sem);
printf("%d
producer
put:
%s
to
Buffer[%d]\n",getpid(),yl2[i-1],*pput_ptr);
}
if(i!=3&&j!=3){
//buff_ptr[*pput_ptr] = '3';
up(cons3_sem);//唤醒消费者,唤醒哪个消费者由生产者生产的
产品决定(if)
printf("%d
producer
put:
%s
to
Buffer[%d]\n",getpid(),yl2[i-1],*pput_ptr);
}
sleep(rate);
}
2、消费者的代码如下:(三个消费者代码相同,只是输出不同)
#include "ipc.h"
int main(int argc,char *argv[]) {
int rate;
//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度
if(argv[1] != NULL)
rate = atoi(argv[1]);
else rate = 3; //不指定为 3 秒
//共享内存 使用的变量
buff_key = 101; //缓冲区任给的键值
buff_num = 2; //缓冲区任给的长度
cget_key = 103; //消费者取产品指针的键值
cget_num = 1; //指针数
shm_flg = IPC_CREAT | 0644;
//共享内存读写权限
//获取缓冲区使用的共享内存,buff_ptr 指向缓冲区首地址
buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg);
//获取消费者取产品指针,cget_ptr 指向索引地址
cget_ptr = (int *)set_shm(cget_key,cget_num,shm_flg);
//信号量使用的变量
prod_key = 203; //生产者同步信号灯键值
pmtx_key = 204; //生产者互斥信号灯键值
cons1_key = 307; //消费者同步信号灯键值
cmtx1_key = 308; //消费者互斥信号灯键值
sem_flg = IPC_CREAT | 0644; //信号灯操作权限
//生产者同步信号灯初值设为缓冲区最大可用量
sem_val = 1;
//获取生产者与消费者同步信号灯,引用标识存 prod_sem
prod_sem = set_sem(prod_key,sem_val,sem_flg);
//消费者初始无产品可取,同步信号灯初值设为 0
sem_val = 0;
//获取消费者同步信号灯,引用标识存 cons_sem
cons1_sem = set_sem(cons1_key,sem_val,sem_flg);
//消费者互斥信号灯初值为 1
sem_val = 1;
//获取消费者互斥信号灯,引用标识存 cmtx_sem
cmtx1_sem = set_sem(cmtx1_key,sem_val,sem_flg);
//循环执行模拟消费者不断取产品
while(1){
//如果无产品消费者阻塞
down(cons1_sem);
//如果另一消费者正在取产品,本消费者阻塞
sleep(rate);
printf("有烟草的抽烟者\n");
char *s="纸,胶水";
//用读一字符的形式模拟消费者取产品,报告本进程号和获取的字符
及读取的位置
printf("%d 有烟草的抽烟者得到: %s\n",getpid(),"纸,胶水");
up(prod_sem);
}
return EXIT_SUCCESS;
}
5.调试及运行
1、 在终端里面输入 make 命令,执行编译和链接
2 打 开 多 个 标 签 页 并 分 别 输
入./producer1 ./producer2 ./consu1 ./consu2 ./consu3 运行程
序 ,
运 行 结 果 如 下 图 所 示 :