先了解几个概念:

临界资源:在一段时间内只允许一个进程访问的资源。

临界区:每个进程中访问临界资源的那段代码称为临界区。

进程互斥:两个或两个以上进程不能同时访问临界资源。

进程同步:异步环境下一组并发进程因相互制约关系而有序的执行。

信号量:对外部资源的一种标识,来表示某种资源是否可用。相当于一种特殊的整形量(原子操作),当请求某种资源时,先判断此资源是否可用,如果可用,则向系统申请该资源,即进行P操作(-1操作),用完该资源后,归还资源,即进行V操作(+1)。

  通常信号量在系统中是以信号量集的方式创建,即用多个信号量来表示系统中多个资源的可用情况。

其生命周期随内核。

函数:

 int semget(key_t key,int nsems,int semflag); //创建信号量

 int semctl(int semid,int semnum,int cmd ...); //删除该信号量

 int semop(int semid,struct sembuf *sops,unsigned nsops);//P、V操作


该信号量是SYSTEM版本的

下面的代码为了更好的体现互斥性,所以只创建了一个信号量。

comm.h
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/types.h>
  4 #include<sys/ipc.h>
  5 #include<sys/sem.h>
  6 #define _PATH_ "."
  7 #define _PROJ_ID_ 0x6666
  8 
  9 union semun
 10 {
 11     int val;
 12     struct semid_ds *buf;
 13     unsigned short  *array;
 14     struct seminfo  *__buf;
 15 };
 16 int creat_sem(int sem_nums);
 17 int get_sem(int sem_nums);
 18 int init_sem(int sem_id,int sem_num,int init_val);
 19 int p_sem(int sem_id,int sem_num);
 20 int v_sem(int sem_id,int sem_num);
 21 int distroy_sem(int sem_id);

comm.c
  1 #include"comm.h"
  2 
  3 static int comm_creat_sem(int flags,int sem_nums)
  4 {
  5     key_t _key = ftok(_PATH_,_PROJ_ID_);
  6     if(_key == -1)
  7     {
  8         perror("ftok");
  9         return -1;
 10     }
 11     int sem_id = semget(_key,sem_nums,flags);
 12     if(sem_id==-1)
 13     {
 14         perror("semget");
 15         return -1;
 16     }
 17     return sem_id;
 18 }
 19 int creat_sem(int sem_nums)
 20 {
 21     int flags = IPC_CREAT|IPC_EXCL|0666;
 22     return comm_creat_sem(flags,sem_nums);
 23 }
 24 int get_sem(int sem_nums)
 25 {
 26     int flags = IPC_CREAT;
 27     return comm_creat_sem(flags,sem_nums);
 28 
 29 }
 30 int init_sem(int sem_id,int sem_num,int init_val)
 31 {
 32     union semun un;
 33     un.val = init_val;
 34     if(semctl(sem_id,sem_num,SETVAL,un,NULL)==-1)
 35     {
 36         perror("semctl");
 37         return -1;
 38     }
 39     return 0;
 40 }
 41 static int op_sem(int sem_id,int sem_num,int op)
 42 {
 43     struct sembuf sem[1];
 44     sem[0].sem_num = sem_num;
 45     sem[0].sem_op = op;
 46     sem[0].sem_flg = 0;
 47     if(semop(sem_id,&sem[0],1)==-1)
 48     {
 49         perror("semop");
 50         return -1;
 51     }
 52     return 0;
 53 }
 54 int p_sem(int sem_id,int sem_num)
 55 {
 56     return op_sem(sem_id,sem_num,-1);
 57 }
 58 int v_sem(int sem_id,int sem_num)
 59 {
 60     return op_sem(sem_id,sem_num,1);
 61 }
 62 int distroy_sem(int sem_id)
 63 {
 64     if(semctl(sem_id,0,IPC_RMID,NULL)==-1)
 65     {
 66         perror("semctl");
 67         return -1;
 68     }
 69     return 0;
 70 }
 
 
 test.c
  1 #include"comm.h"
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6     int sem_id = creat_sem(1);
  7     if(sem_id==-1)
  8     {
  9         return -1;
 10     }
 11     init_sem(sem_id,0,1);
 12     pid_t id = fork();
 13     if(id<0)
 14     {
 15         perror("fork");
 16         exit(1);
 17     }
 18     else if(id == 0)
 19     {
 20         int sem_id = get_sem(0);
 21         while(1)
 22         {
 23             p_sem(sem_id,0);
 24 
 25             printf("A");
 26             fflush(stdout);
 27             sleep(1);
 28             printf("A");
 29             fflush(stdout);
 30             sleep(2);
 31 
 32             v_sem(sem_id,0);
 33         }
 34     }
 35     else
 36     {
 37         while(1)
 38         {
 39             p_sem(sem_id,0);
 40 
 41             printf("B");
 42             fflush(stdout);
 43             sleep(1);
 44             printf("B");
 45             fflush(stdout);
 46             sleep(3);
 47 
 48             v_sem(sem_id,0);
 49         }
 50         waitpid(id,NULL,0);
 51         distroy_sem(sem_id);
 52 
 53     }
 54     return 0;
 55 }
 
 结果:
 //不加信号量:(由于对临界资源(显示屏)的竞争,打印结果出现是交叉的)
 [fbl@localhost sem]$ ./test
  BABAABABAABBAABABAABABAABBAABABAABABAA^C
  //加入信号量:
 [fbl@localhost sem]$ ./test
 BBAABBAABBAABBAABBA^C

静态库打包:

Makefile:
  1 libmysem.a:comm.o
  2     ar rcs $@ $^
  3 comm.o:comm.c
  4     gcc -c $<
  5 .PHONY:clean
  6 clean:
  7     rm -rf libmysem.a comm.o output
  8 .PHONY:output
  9 output:
 10     mkdir output
 11     cp libmysem.a output
 12     cp comm.h output
 13