一.对信号量的理解

    信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。

    当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,小于0,无资源可用,进程会进入睡眠状态直至资源可用。当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操作均为原子操作。

二.使用信号量的原因

    防止出现因多个程序同时访问一个共享资源时而引发的一系列问题。而信号量可以让一个临界区同一时间只有一个线程在访问。

    临界区:访问临界资源的一段代码。

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

三.信号量的工作原理

    信号量只能进行两种操作:等待和发生信号。P(sv)和V(sv)。

    P(sv):如果sv 的值大于0,就给它-1;如果等于0,就挂起该进程。

    V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行。如果没有进程因等待sv 而被挂起,就给它+1。

四.代码部分

sem.h

  1 #include<stdio.h>

  2 #include<string.h>

  3 #include<sys/types.h>

  4 #include<sys/ipc.h>

  5 #include<sys/sem.h>

  6 

  7 #define _PATH_  "."

  8 #define _PROJ_ID_ 0x4344

  9 union semun {

 10                int              val;

 11                struct semid_ds *buf;

 12                unsigned short  *array;

 13                struct seminfo  *__buf;

 14            };  

 15            

 16 

 17 static int comm_create_sem_set(int _sem_nums,int flags);

 18 int create_sem_set(int _sem_nums); 

 19 int get_sem_set(int _sem_nums);

 20 int init_sem_set(int _sem_id);

 21 int p_sem_elem(int _sem_id,int _seq_num);

 22 int v_sem_elem(int _sem_id,int _seq_num);

 23 int destroy_sem_set(int _sem_id);


sem.c

  1 #include "sem.h"

  2 static int comm_create_sem_set(int _sem_nums,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=semget(_key,_sem_nums,flags);

 11         if(sem_id<0)

 12         {

 13                 perror("semget");

 14                 return -1;

 15         }

 16         return sem_id;

 17 }

 18 int create_sem_set(int _sem_nums)

 19 {

 20         int flag=IPC_CREAT|IPC_EXCL|0666;

 21         return comm_create_sem_set(_sem_nums,flag);

 22 }

 23 int get_sem_set(int _sem_nums)

 24 {

 25         return comm_create_sem_set(_sem_nums,IPC_CREAT);

 26 }

 27 int init_sem_set(int _sem_id)

 28 {

 29         union semun _un;

 30         _un.val=1;

 31         int ret=semctl(_sem_id,0,SETVAL,_un);

 32         if(ret<0)

 33         {

 34                 perror("semctl");

 35                 return -1;

 36         }

 37         return ret;

 38 }

 39 static int op_sem(int _sem_id,int op,int _seq_num)

 40 {

 41         struct sembuf sem;

 42         memset(&sem,'\0',sizeof(sem));

 43         sem.sem_num=_seq_num;

 44         sem.sem_op=op;

 45         sem.sem_flg=0;

 46         if(semop(_sem_id,&sem,1)<0)

 47         {

 48                 perror("semop");

 49                 return -1;

 50         }

 51 

 52         return 0;

 53 }

 54 int p_sem_elem(int _sem_id,int _seq_num)

 55 {

 56         return op_sem(_sem_id,-1,_seq_num);

 57 }

 58 int v_sem_elem(int _sem_id,int _seq_num)

 59 {

 60         return op_sem(_sem_id,1,_seq_num);

 61 }

 62 int destroy_sem_set(int _sem_id)

 63 {

 64         if(semctl(_sem_id,0,IPC_RMID,NULL)<0)

 65         {

 66                 perror("semctl");

 67                 return -1;

 68         }

 69         else

 70         {

 71                 printf("destroy sem success\n");

 72         }

 73         return 0;

 74 }


测试代码test.c

  1 #include "sem.h"

  2 int main()

  3 {

  4         pid_t id=fork();

  5         if(id<0)

  6         {

  7                 perror("fork");

  8                 return -1;

  9         }

 10         else if(id==0)

 11         {

 12                 int sem_id=create_sem_set(1);

 13                 init_sem_set(sem_id);

 14                 while(1)

 15                 {

 16                         p_sem_elem(sem_id,0);

 17                         printf("A");

 18                         fflush(stdout);

 19                         sleep(2);

 20                         printf("A");

 21                         fflush(stdout);

 22                         sleep(2);

 23                         v_sem_elem(sem_id,0);

 24                 }

 25         }

 26         else

 27         {

 28                 sleep(6);

 29                 int sem_id=get_sem_set(1);

 30                 while(1)

 31                 {

 32                         p_sem_elem(sem_id,0);

 33                         printf("B");

 34                         fflush(stdout);

 35                         sleep(2);

 36                         printf("B");

 37                         fflush(stdout);

 38                         sleep(2);

 39                         v_sem_elem(sem_id,0);

 40                 }

 41         }

 42         return 0;

 43 }


makefile的编写:

  1 test:test.c sem.c

  2         gcc -o $@ $^

  3 .PHONY:clean

  4 clean:

  5         rm -f test


运行结果:

wKiom1cV2zfDJ0VzAAAyjYhm-cY892.png