进程间通信之信号量

信号量:相当于一个计数器,计录当前环境某种资源个数。没有对信号进行传输,保证对信号量操作是原子的。主要为了保护临界资源。生命周期随内核。

临界区:访问共享资源的代码区

临界资源:进程间所共享的资源

互斥:同一时刻,只允许一个进程对这份资源访问,这个进程对资源具有独占性,排他性。

同步:互斥情况下,进程对临界资源访问具有顺序。

信号量有两个基本操作:P,V

p:减一,向信号量申请资源,申请到后若p=0,则将进程挂起,否则信号量减一。

v:加一,使用资源完毕,归还给系统,若有进程挂起,则唤醒等待进程或线程,否则将信号量加一。

使用到的主要函数原型:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h> 

int semget(key_t key, int nsems, int semflg);

int semctl(int semid, int semnum, int cmd, ...);

int semop(int semid, struct sembuf *sops, unsigned nsops);

union semun {

               int              val;    /* Value for SETVAL */

               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */

               unsigned short  *array;  /* Array for GETALL, SETALL */

               struct seminfo  *__buf;  /* Buffer for IPC_INFO

                                           (Linux-specific) */

           };

 struct sembuf{

          unsigned short sem_num;  /* semaphore number */

           short          sem_op;   /* semaphore operation */

           short          sem_flg;  /* operation flags */

          }中sem_flg表示以什么形式控制信号量,0表示默认,SEM_NODO表示取消

注意:信号量的创建是以信号量集的形式创建

    当semctl(semid,semnum,cmd);要删除时cmd被设置为IPC_RMID,semnum被忽视。当cmd为SETVAL时,对第semnum个信号量初始化。

   信号量集中信号量从0开始

grep  -ER 'semum' /usr/include/  查询semum

//comm.h
  1 #pragma once
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/ipc.h>
  7 #include<sys/sem.h>
  8 #define _PATH_ "."
  9 #define _PROJ_ID_ 0x8888
 10 union semun
 11 {
 12     int val;
 13     struct semid_ds* buf;
 14     unsigned short  *array;
 15     struct seminfo  *__buf;
 16 };
 17 //struct sembuf
 18 //{
 19 //  unsigned short sem_num;
 20 //  short sem_op; 
 21 //  short sem_flg;
 22 // };
 23 static int _sem_set(int snum,int flags);
 24 static int sem_op(int sem_id,int nsops,int flags);
 25 int create_sem(int snum);
 26 int get_sem(int snum);
 27 int init_sem(int sem_id,int snum,int unit_val);
 28 int sem_p_element(int sem_id,int nsops);
 29 int sem_v_element(int sem_id,int nsops);
 30 int destory_sem_element(int sem_id);
 //comm.c
  1 #include"comm.h"
  2 static int _sem_set(int snum,int flags)
  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=-1;
 11     sem_id=semget(_key,snum,flags);
 12     if(sem_id<0)
 13     {
 14        
 15         perror("semget");
 16         return -1;
 17     }
 18     return sem_id;
 19 }
 20 
 21 int create_sem(int snum)
 22 {
 23     int flags=IPC_CREAT|IPC_EXCL|0666;
 24     int ret= _sem_set(snum,flags);
 25     return ret;
 26 }
 27 int get_sem(int snum)
 28 {
 29     return _sem_set(snum,IPC_CREAT);
 30 }
 31 int init_sem(int sem_id,int snum,int unit_val)
 32 {
 33     union semun _un;
 34     _un.val=unit_val;
 35     if(semctl(sem_id,snum,SETVAL,_un)<0)
 36     {
 37             perror("semctl\n");
 38         return -1;
 39     }
 40     return 0;
 41 }
 42 static int sem_op(int sem_id,int seqnum,int op)
 43 {
 44     struct sembuf _sm;
 45     _sm.sem_num=seqnum;
 46     _sm.sem_op=op;
 47     _sm.sem_flg=0;
 48     if(semop(sem_id,&_sm,1)<0)
 49     {
 50         perror("semop");
 51         return -1;
 52     }
 53     return 0;
 54 }
 55 int sem_p_element(int sem_id,int seqnum)
 56 {
 57     return sem_op(sem_id,seqnum,-1);
 58 }
 59 int sem_v_element(int sem_id,int seqnum)
 60 {
 61     return sem_op(sem_id,seqnum,1);
 62 }
 63 int destory_sem_element(int sem_id)
 64 {
 65     if(semctl(sem_id,IPC_RMID,0,NULL)<0)
 66     {
 67         perror("semctl\n");
 68         return -1;
 69     }
 70     return 0;
 71 }
 //test.c
  1 #include"comm.h"
  2 int main()
  3 {
  4     int sem_id=create_sem(1);
  5     if(sem_id<0)
  6     {
  7         printf("error\n");
  8         return -1;
  9     }
 10     init_sem(sem_id,1,1);
 11     pid_t pid=fork();
 12     if(pid<0)
 13     {
 14         perror("pid");
 15         return -1;
 16     }
 17     else if(pid==0)
 18     {
 19         int sem_pid=get_sem(1);
 20         while(1)
 21         {
 22             sem_p_element(sem_pid,0);
 23             printf("A");                                 
 24             sleep(1);
 25             fflush(stdout);
 26             printf("A");
 27             sleep(8);
 28             fflush(stdout);
 29             sem_v_element(sem_pid,0);
 30         }
 31     }
 32     else
 33     {
 34         while(1)
 35         {
 36             sem_p_element(sem_id,0);
 37             sleep(3);
 38             printf("B");
 39             sleep(2);
 40             fflush(stdout);
 41             printf("B");
 42             sleep(5);
 43             fflush(stdout);
 44             sem_v_element(sem_id,0);
 45         }        
 46         waitpid(pid,NULL,0);
 47         destory_sem_element(sem_id);
 48  
 49     }
 50     return 0;
 51 }
 //Makefile
  1 .PHONY:all
  2 all:test
  3 test:test.c comm.c
  4     gcc -o $@ $^
  5 .PHONY:clean
  6 clean:
  7     rm -f test

未使用信号量之前:进程间通信之信号量

使用后:

进程间通信之信号量