一.对信号量的理解
信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。
当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于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
运行结果: