一、什么是信号量

    就是一种用来描述某种资源数量个数的计数器,通过控制其他通信资源来实现进程通信。它在此过程中负责数据的互斥、同步等。互斥,就是在同一时间段内,A、B两个进程只有一个进程在运行。同步。就是A 进程完成之后,B进程接着完成,有一定的执行顺序。

二、工作原理

    两种操作模式,P操作和V操作。

    P操作(就是申请资源,信号量进行减一操作)

    V操作(释放资源,信号量进行加一操作)

三、 ipcs -s 查看semid

   ipcrm -s id 删除id

四、主要函数

    shmget 创建信号量

    shmctl 删除

    shmop P/V 操作

    函数原型: int semop(int sem_id,struct sembuf *sops,size_t nsops);

    sem_id 就是通过shmget函数创建得到的

    struct sembuf *sops 参数sops指向一个结构体数组中,每个sembuf结构体对应一个信号的操作。结构体如下

     struct sembuf

    {

        unsigned short sem_num;//sem_num是信号集中的索引,0代表第一个,1,代表第二个。。。    

        short     sem_op; //操作类型,1 -->V操作,-1-->P操作

        short     sem_flg; //操作标志   

 };

    sem_flg标志有两种 IPC_NOWAIT 或 SEM_UNDO 两种。如果操作指定 SEM_UNDO(我下面给的是0),它将会自动撤销该进程在终止时

     nsops 就是sops 的个数

~~ ~~~~~~~~~~ ~~~~********** man 函数名可查看函数的用法**********~~~~~~~~~~~~~~~~~~~

五、代码实现

    comm.h

   #pragma once
   #include<stdio.h>
   #include<stdlib.h>
   #include<unistd.h>
   #include<sys/types.h>
   #include<sys/ipc.h>
   #include<sys/sem.h>
   #define _PATH_ "."
   #define _PROG_ID_ 0x6675
  
   union semun
   {
      int val;
      struct semid_ds *buf; 
      unsigned short *array;
      struct seminfo *__buf;
  };
  int creatSem(int nsems);
  int get_Sem();
  int initSem(int sem_id,int Which);
  int destroySem(int sem_id);
  int V_Sem(int sem_id,int which);
  int P_Sem(int sem_id,int which);
  static int op_Sem(int sem_id,int op,int which);

 comm.c

   #include"comm.h"
   int creatSem(int nsems)
   {
       key_t  _key=ftok(_PATH_,_PROG_ID_);
       if(_key<0)
       {
           perror("ftok");
           return -1;
       }
      umask(0);
      int sem_Flg=IPC_CREAT|IPC_EXCL|0666;
      int sem_id=semget(_key,nsems,sem_Flg);
      if(sem_id<0)
      {
          perror("semget");
          return -1;
      }
      return sem_id;
  }
  
  int get_Sem()
  {
      key_t k=ftok(_PATH_,_PROG_ID_);
      return semget(k,0,0);
  }
  static int op_Sem(int sem_id,int op,int which)
  {
      struct sembuf sem;
      sem.sem_num=which;
      sem.sem_op=op;
      sem.sem_flg=0;
      return semop(sem_id,&sem,1);
  
  }
  
  int initSem(int sem_id,int Which)
  {
      union semun _semum;
      _semum.val=1;
     int ret= semctl(sem_id,Which,SETVAL,_semum);
     if(ret==-1)
     {
             perror("semctl");
             return ret;
     }
     return ret;
  }
  int P_Sem(int sem_id,int which)
  {
      int ret=op_Sem(sem_id,-1,which);
      if(ret==-1)
     {
          perror("p_sem");
          return -1;
      }
          return ret;
  
 }
  int V_Sem(int sem_id,int which)
  {
      int ret=op_Sem(sem_id,1,which);
      if(ret==-1)
      {
          perror("V_Sem");
          return ret;
      }
      return ret;
  }
  
  int destroySem(int sem_id)
  {
      int ret=semctl(sem_id,0,IPC_RMID,NULL);
      if(ret==-1)
      {
          perror("semtrl");
          return -1;
      }
      return ret;
  
  }

my_shm.c

    #include"comm.h"
   int main()
   {
        int sem_id=creatSem(1);
       initSem(sem_id,0);
       pid_t id=fork();
       if(id<0)
       {
           perror("for");
          return -1;
      }
      else if(id==0)
      {
          int sem_id=get_Sem();
          while(1)
         {
  
              P_Sem(sem_id,0);
              printf("A");
              fflush(stdout);
              sleep(1);
              printf("A");
              fflush(stdout);
              sleep(2);
              V_Sem(sem_id,0);
          }
  
      }else
      {
          while(1)
          {
              P_Sem(sem_id,0);
              printf("B");
              fflush(stdout);
              sleep(1);
              printf("B");
              fflush(stdout);
              sleep(1);
              V_Sem(sem_id,0);
          }
          waitpid(id,NULL,0);
      }
  
  }

 不用信号量之前(如下图)可以看出打印结果是随机的 。

wKioL1cQhX-BTurAAAFTOsROepo339.jpg 加了信号量之后(如下图)(都是成对出现的,因为是互斥的)

wKiom1cQhQ2TpqSrAAME82F-5Mk793.jpg