Linux下IPC:信号量与共享内存详解

    蛋疼了很久,漏了一个括号,结果在shmat返回错误Identifier removed...废话不多说,最后解释。。
    信号量,很多人把他和mutex进行类比,是的,可以简单认为mutex是信号量只在0-1变化的。不过二者还是有些差别的(现在我还没深入到。。),信号量表示资源数,如果信号量大于0,则表示他还有val个资源可以被获取,当val<=0时候表示没有信号量了,这里出现小于0是表示有多少进程在等待。
    共享内存使得多个进程能够通过共享的内存区域进行通信。这个最大的好处就是在server/client上实现二者通信。
    但是共享内存的过程有个同步问题随之而来,server什么时候去取得共享区域数据,什么时候不能取呢,我首先想到的就是用信号呗,确实,不过这里有个条件,client要知道server的pid,server也要知道client的pid,这个当然也是可以的。
    还有一种方法就是采用信号量的方式(可以暂时理解成用锁的形式)来阻塞某一端,直至数据准备就绪再去取得数据。
我这里用个网络上很流行的案例,server-client
---------------------------------------
设计目的:实现client向server传递数据,只有在client发送完毕后,server才取得数据,否则阻塞等待。
设计思路:1、首先运行服务器,创建一个共享内存区域,存放数据;
              2、同时创建一个semid,注意,信号量一般是多个(不像mutex就是一个0-1状态,这里semid表示信号量的id)
int semid=semget(ket_t key,int nsems,int flag)   key就是IPC的键了,nsems表示这个semid里有多少个信号量,flag表示权限,一般IPC_CREAT|IPC_EXCL|0666(注意下,IPC_EXCL这个表示如果key已经被绑定过则报错,这个在服务器里可以使用,但是客户机上就不要用IPC_EXCL当然IPC_CREAT也不用了),创建好semid。
              3、这里细致说下sembuf和union semun
                  struct sembuf{
                        unsigned short sem_num;//表示semid的第几个信号量0开始计数
                        short sem_op;//表示semop()函数后的操作,正:则向val加上sem_op;负:则val+(sem_op);当然也可以为0
                          short sem_flg;//IPC_NOWAIT   SEM_UNDO
                  }

                  union semun{
                          int val;//这个表示信号量的资源数 很关键的数,就是上面说的val
                  }

                4、后面的步骤就是围绕这些进行,看代码把
--------------------server--------------------------------------------

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 
  10 #define SEM_KEY 4001
  11 #define SHM_KEY 5678
  12
  15 
  16 
  17 int semid,shmid;
  18 int *shmptr;
  19 struct sembuf sembuf1;
  20 union semun {
  21         int val;
  22 };
  23 
  24 int main(void)
  25 {
  26         //create a shm  
  27         if((shmid = shmget(SHM_KEY,sizeof(int),IPC_CREAT|0666))<0){
  28                 printf("create shm error\n");
  29                 retur;
  30         }
  31         if((shmptr = shmat(shmid,NULL,0))==(int*)-1){
  32                 printf("shmat error:%s\n",strerror(errno));
  33                 return 1;
  34         }
  35         semid = semget(SEM_KEY,2,IPC_CREAT|0666);//这里是创建一个semid,并且有两个信号量
 36         union semun semun1;//下面这四行就是初始化那两个信号量,一个val=0,另一个val=1
 37         semun1.val=0;
 38         semctl(semid,0,SETVAL,semun1);
 39         semun1.val=1;
 40         semctl(semid,1,SETVAL,semun1);
  41 
  42         //
  43         while(1){
  44                 sembuf1.sem_num=0;//sem_num=0指的是下面操作指向第一个信号量,上面设置可知其                                                       //val=0
  45                 sembuf1.sem_op=-1; //这里定义操作是-1,但是他已经为0 了,所以会阻塞,48行就产生                                                       //了这个阻塞
  46                 sembuf1.sem_flg=SEM_UNDO;
  47 
  48                 semop(semid,&sembuf1,1);//服务器在这里会阻塞,下面看下client
  49                 printf("the NUM:%d\n",*(shmptr));//输出结果
  50 
  51                 sembuf1.sem_num=1;//这里让客户端再次就绪,就这样循环
  52                 sembuf1.sem_op=1;
  53                 sembuf1.sem_flg=SEM_UNDO;
  54 
  55                 semop(semid,&sembuf1,1);
  56         }
  57         return 0;
  58 }


--------------------------client-------------------------------
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 
  8 #define SEM_KEY 4001
  9 #define SHM_KEY 5678
  10
  13 
  14 
  15 int semid,shmid;
  16 int *shmptr;
  17 struct sembuf sembuf1;
  18 union semun {
  19         int val;
  20 };
  21 
  22 int main(void)
  23 {
  24         //create a shm
  25         if((shmid = shmget(SHM_KEY,sizeof(int),0666))<0){
  26                 printf("create shm error\n");
  27                 return 1;
  28         }
  29         if((shmptr =shmat(shmid,NULL,0))==(int*)-1){
  30                 printf("shmat error\n");
  31                 return 1;
  32         }
  33         semid = semget(SEM_KEY,2,0666);
  34         union semun semun1;
  35 
  36         //
  37         while(1){
  38                 sembuf1.sem_num=1;//这里指向第2个信号量(sem_num=1)
  39                 sembuf1.sem_op=-1;//操作是-1,但是第二个信号量初始值为1,所以下面不会阻塞
  40                 sembuf1.sem_flg=SEM_UNDO;
  41 
  42                 semop(semid,&sembuf1,1);//继续
  43                 scanf("%d",shmptr);   //用户客户端输入数据
  44 
  45                 sembuf1.sem_num=0;//这里指向第一个信号量
  46                 sembuf1.sem_op=1;//操作加1
  47                 sembuf1.sem_flg=SEM_UNDO;
  48 
  49                 semop(semid,&sembuf1,1);//执行+1后,我们发现,服务器阻塞正是由于第一个信号量为0,无法减一,而现在客户端先为其加1,那服务器就绪!客户端继续循环,发现第二个信号量已经减为0,则阻塞了,我们回到服务器
  50         }
  51         return 0;
  52 }
--------------------------------------------------------------

Linux下IPC:信号量与共享内存详解

Linux下IPC:信号量与共享内存详解

你可能感兴趣的:(Linux下IPC:信号量与共享内存详解)