信号量与共享存储区(操作系统实验三)
实验目的:
1.熟悉Linux环境下的多进程编程
2.熟悉Linux的信号量与共享存储区的使用
3.加深对生产者/消费者(PC)问题的理解
实验环境:
Ubuntu 12.4(32位,简体中文)
实验内容:
1.编写程序,构建父进程逻辑与紫子进程逻辑框架;
2.对信号量操作进行再次封装,实现以下函数:
MySem newsem(int initVal)
:创建新的信号量,初值为initVal,完成后返回信号量的ID(typedef int MySem;)
void psem(MySem semID):对ID为semID的信号量做p
void vsem(MySemsemID):对ID为semID的信号量做v
void freesem(MySemsemID):注销ID为semID的信号量
3.在init()中添加代码,请求用户输入仓库库存,然后申请并初始化共享存储区(仓库数组和变量in、out),以及所各种信号量。
4.在Pro()和Con()中添加代码,完成复杂PC问题(多生产者、多消费者)的模拟。
其中Pro()和Con()开始时在屏幕显示
<进程类型(P或C)> <进程id> started.
结束时Pro()显示:P <进程id> put an item to <仓库位置>.
Con()显示:C <进程id> got an item from <仓库位置>.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<time.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<sys/types.h>
#include<sys/ipc.h>
#define PRO 1
#define CON 0
#define p -1
#define v +1
int empty,full,mutex1,mutex2;
int *buf;
int newsem(int intval) //新建信号量
{
int r,semID;
semID=semget(0,1,IPC_CREATE|0666); //创建新的信号量集并可读写
r=semctl(semID,0,SETVAL,intval); //对制定信号量赋值为intval,若成功则,返回一个正数,否则返回一个负数;
return semID;
}
void psem(int semID) //对ID为semID的信号量做p操作;
{
struct sembuf s;
s.sem_num=0; //欲操作的信号量在信号集中的编号
s.sem_op=p; //信号量PV操作的增量
s.sem_flg=0; //额外选项标识(0表示无额外设置,IPC_NOWAIT表示不允许阻塞,SEM_UNDO表示进程结束时回复信号量等)
int r=semop(semID,&s,1); //对指定的semID信号量执行p操作
}
void vsem(int semID) //对ID为semID的信号量做操作;
{
struct sembuf s;
s.sem_num=0; //欲操作的信号量在信号集中的编号
s.sem_op=v; //信号量PV操作的增量
s.sem_flg=0; //额外选项标识(0表示无额外设置,$
int r=semop(semID,&s,1); //对指定的semID信号量执行v操作
}
void freesem(int semID)
{
int r;
r=semctl(semID,0,IPC_RMID); //IPC_RMID:表示注销信号量集,不需要参数;
}
int init(int n)
{
int shpid;
shpid=shmget(0,sizeof(int)*(n+2),IPC_CREAT|0666);//create共享存储区+2 in out
buf=(int *)shmat(shpid,0,0); //将共享存储区映射到用户进程空间;
empty=newsem(n); //缓冲区单元格有n个,初始化标记为null,允许生产者进程一开始就连续执行k次;
full=newsem(0); //初始时,没有满标记单元格,置初值full=0;
mutex1=newsem(1); //生产者的互斥;
mutex2=newsem(1); //消费者的互斥;
buf[n]=0; //缓冲区单元格in;
buf[n+1]=0; //缓冲区单元格out;
return shpid; //存储区id;
}
void pro()
{
}
void con()
{
}
int main()
{
int t,k,n;
printf("请输入仓库库存n:\n");
scanf("%d",&n);
int shpid=init(n);
k=rand()%1+1;
pid_t pid; //定义进程标示符;
while(1)
{
srand((unsigned)time(NULL)); //每次置随机数种子;
pid=fork(); //建立一个新的子进程,在父进程返回的时子进程的ID,在子进程返回0;
if(pid==0) //子进程;
{
t=rand()%2; //0,1
if(t==PRO)
pro(pid,n);
else if(t==CON)
con(pid,n);
return 0;
}
else //父进程;
sleep(rand()%3);
}
int x1=shmdt(0); //断开已有的映射
int x2=shctl(shpid,IPC_RMID,0);
return 0;
}
未完待续;