zoukankan      html  css  js  c++  java
  • 复杂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
    ",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>
    ",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
    ",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>
    ",getpid(),index);
      vsem(mutex2);
      vsem(empty);
    }
    int main()
    {
       int t,k,n;
       printf("Please input 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;
    }
    

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

  • 相关阅读:
    SpringBoot(三)SpringApplication启动类准备阶段
    SpringBoot(四)SpringApplication启动类运行阶段 SpringApplicationRunListener
    201871010104陈园园 《面向对象程序设计(java)》第八周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第十周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第四周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第二周学习总结 陈园园
    《2019面向对象程序设计(java)课程学习进度条》 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第七周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计 (java)》第一周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第六——七周学习总结 陈园园
  • 原文地址:https://www.cnblogs.com/france/p/4808551.html
Copyright © 2011-2022 走看看