#include <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/types.h> #include <time.h> #include <stdlib.h> #include <sys/shm.h> #define PRO 1 #define CON 0 #define P -1 #define V +1 typedef int MySem; MySem empty,full,mutex1,mutex2; int *buf; MySem newsem(int intVal)// 新建信号量 { int r,semID; semID=semget(0,1,IPC_CREAT|0666); //创建新信号量集 r=semctl(semID,0,SETVAL,intVal); //对指定信号量赋intVal值 返回值:如果成功,则为一个正数;如果失败,则为-1 return semID;//获得的信号量的标识,用于此后的信号量操作 } void psem(MySem semID)//对ID为semID的信号量做p { struct sembuf s; s.sem_num=0; s.sem_op=P; s.sem_flg=0; int r=semop(semID,&s,1);//对指定的信号量执行P操作 } void vsem(MySem semID)//对ID为semID的信号量做v { //unsigned short sem_num; 欲操作的信号量在信号量集中的编号 //short sem_op; 信号量PV操作的增量(例如+1或-1) //short sem_flg; 额外选项标识(0表示无额外设置;IPC_NOWAIT表示不允许阻塞; //SEM_UNDO表示进程结束时恢复信号量 等)}; struct sembuf s; s.sem_num=0; s.sem_op=V; s.sem_flg=0; int r=semop(semID,&s,1);//对指定的信号量执行V操作 } void freesem(MySem semID)//注销ID为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(pid_t pid,int n) { printf("<P> <%d> started\n",getpid());//取得进程识别码 旧版 新_getpid(); int index=buf[n]; //buf[n]->in 用来标识in的位置 psem(empty); //同步,如果没有足够p值的话会放入队列中,系统进行维护 psem(mutex1); buf[n]=(buf[n]+1)%n; buf[ buf[n]]=1;//模拟存入,置1 printf("P <%d> put an item to <%d>\n",getpid(),index); vsem(mutex1);//回调p函数,取出队首, vsem(full); } /* demo: n=3 p:index = buf[3] =in=0 in=buf[3]=1 buf[1]=1 p:index = buf[3] =in=1 in=buf[3]=2 buf[2]=1 v:index = buf[4] =out=0 out=buf[4]=1 buf[1]=0 v:index = buf[4] =out=1 out=buf[4]=2 buf[2]=0 v:index = buf[4] =out=2 psem(full) 等待释放 p:index = buf[3] =in=2 in=buf[3]=0 buf[0]=1 回调v v:out=buf[4]=0 buf[0]=0 .... */ void con(pid_t pid,int n) { printf("<C> <%d> started\n",getpid()); int index=buf[n+1];//out psem(full); psem(mutex2); buf[n+1]=(buf[n+1]+1)%n; buf[buf[n+1]]=0;//模拟取出,置0 printf("C <%d> got an item from <%d>\n",getpid(),index); vsem(mutex2); vsem(empty); } int main() { int t,k,n; printf("Please input 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; //记得return } else //父进程 sleep(k); } int x1=shmdt(0);//断开已有的映射 int x2=shctl(shpid,IPC_RMID,0); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
today lazy . tomorrow die .