一.信号量

   信号量是一种数据操作锁,本身不具有数据交换功能,而是通过控制其他的通信资源来实现进程之间的通信,简单来讲,信号量相当于一个计数器,计数当前某种资源的个数。信号量的周期也是随内核的。为了解决多个程序同时访问一个共享资源引发的问题。

    临界资源:多个进程能访问到的公共资源。

    临界区:将能访问带临界资源的代码成为临界区。

  同步:对临界资源的访问具有顺序性。

   pv 操作:

   p(sv)  sv>0 减1  sv=0   挂起的该进程执行

   s(sv)  没有进程因等待sv而挂起就加1,有进程等待sv被挂起,就恢复运行。

  信号量用到的函数:

  int semget(key_t key,int nsems,int smflag)//nsems:信号量个数

  以信号量集为基本单位进行申请。

 int semctl(int semid, int semnum, int cmd, ...);//semnum:第几个信号量

   struct sembuf

{

   unsigned short sem_num;

   short sem_op;

   short sem_flg;

}

第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信 号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。

最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量, 如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清理我们的信号量。

semnu 的联合体,初始化信号量的时候用得到:

union semun {
    int val;
   struct semid_ds *buf;
   unsigned short *array;
           };




   信号量实现进程间通信:

 //comm.h
  1 
  2 #pragma once
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 #include<stdio.h>
  6 #include<sys/types.h>
  7 #include<sys/sem.h>
  8 #include<sys/ipc.h>
  9 #define _PATH_ "."
 10 #define _PROJ_ID_ 0x7777
 11 
 12 union semun
 13 {
 14    int val;
 15    struct semid_ds *buf;
 16    unsigned short *array;
 17    struct seminfo *_buf;
 18 };
 19  static int comm(int __sem_nums,int flag);
 20 int create_sem_set(int _sem_nums);
 21 int get_sem_set(int _sem_nums);
 22 int init_sem_set(int _sem_id,int _sem_num,int _sem_val);
 23 int p_sem_elem(int _sem_id ,int _sem_num);
 24 int v_sem_elem(int _sem_id,int _sem_num);
 25 int destroy_sem(int _sem_id);
~ 

//comm.c

  1 #include"comm.h"
  2 static int comm(int _sem_nums,int flag)
  3 {
  4   key_t key=ftok(_PATH_,_PROJ_ID_);
  5   if(key<0)
  6   {
  7     perror("ftok");
  8     return -1;
  9   }
 10   int sem_id=semget(key,_sem_nums,flag);
 11   if(sem_id<0)
 12   {
 13     perror("semget");
 14     return -1;
 15   }
 16 
 17   return sem_id;
 18 
 19 }
 20  int create_sem_set(int _sem_nums)
 21 {
 22   int flag=IPC_CREAT|IPC_EXCL|0666;
 23   return comm(_sem_nums,flag);
 24 
 25 
 26 }
 27 int get_sem_set(int _sem_nums)
 28 {
 29    int flag=IPC_CREAT;
 30    return comm(_sem_nums,flag);
 31 }
 32 int init_sem_set(int _sem_id,int _sem_num,int _sem_val)
 33 {
 34    union semun _un;
 35    _un.val=_sem_val;
 36    if(semctl(_sem_id,_sem_num,SETVAL,_un)<0)
 37    {
 38     perror("semctl");
 39     return -1;
 40 
 41     }
 42    return 0;
 43   }
 44 int p_sem_elem(int _sem_id ,int _sem_num)
 45 {
 46    struct sembuf _sem_buf[1];
 47    _sem_buf[0].sem_num=_sem_num;
 48    _sem_buf[0].sem_op=-1;
 49    _sem_buf[0].sem_flg=0;
 50 if(semop(_sem_id,_sem_buf,1)<0)
 51   {
 52   perror("semop");
 53   return -1;
 54 
 55   }
 56   return 0;
 57 }
 58 int v_sem_elem(int _sem_id,int _sem_num)
 59 {
 60    struct sembuf _sem_buf[1];
 61    _sem_buf[0].sem_num=_sem_num;
 62    _sem_buf[0].sem_op=1;
 63    _sem_buf[0].sem_flg=0;
 64 if(semop(_sem_id,_sem_buf,1)<0)
 65   {
 66     perror("semop");
 67     return -1;
 68 
 69   }
 70   return 0;
 71 
      }
 74 int destroy_sem(int _sem_id)
 75 {
 76   if(semctl(_sem_id,0,IPC_RMID,NULL)<0)
 77   {
 78   perror("semctl");
 79    return -1;
 80 
 81 
 82   }
 83 return 0;
   }
   
   
 91 int main()
 92 {
 93   int sem_id=create_sem_set(1);
 94   init_sem_set(sem_id,0,1);
 95   pid_t pid=fork();
 96   if(pid<0)
 97   {
 98    perror("fork");
 99    exit(1);
100   }
101 
102   else if(pid==0)
103   {
104       int sem_id=get_sem_set(1);
105       while(1)
106       {
107         p_sem_elem(sem_id,0);
108         printf("A");
109         sleep(1);
110        fflush(stdout);
111        printf("A");
112        sleep(7);
113        fflush(stdout);
114        v_sem_elem(sem_id,0);                                                         116      }
117  }
118 
119   else
120   {
121      while(1)
122     {
123       p_sem_elem(sem_id,0);
124 
125       printf("B");
126       sleep(2);
127       fflush(stdout);
128       printf("B");
129       sleep(5);
130       fflush(stdout);
131       v_sem_elem(sem_id,0);
132 
133 
134     }
135  }                                                                                        return 0;
   }

程序运行结果:

wKioL1cQ85LAtRJBAAAgOb0l7OQ750.png

总结:

   上述程序中显示器就相当于公共资源,父子进程都想要访问,在其上面输出自己的内容,就必须使用信号量,这样就防止了两个同时输出引发的问题,两个进程只能一个访问完,另一个在访问。