复杂PC问题——信号量与共享存储区

#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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted on 2015-06-09 22:19 france 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/france/p/4808551.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值