(1)信号量的基本概念:
信号量的本质是一种数据操作锁,它的本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号在此过程中负责数据操作的互斥,同步等功能。
当请求一个信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。如果大于0,表示资源可以用,等于0表示没有可用资源,这个时候进程会进入睡眠状态直至有资源可用。
当进程不再使用一个信号量来控制共享资源时,信号量的值加1,对信号量的值进行的增减操作均属于原子操作,这个因为信号量主要的作用是维护资源的互斥或多进程的同步访问。
注意:1,一个信号量的生命周期是随内核的。2,信号量必须能够被其他的进程看到。3,查看信号量的命令:ipcs -s。
(2)信号量的使用:
由于信号量只能进行两种操作,分别是等待信号和发送信号,即P(sv)和V(sv)。
P(sv):如果sv的值大于0,就减一,如果它等于零表示该进程挂起(进程的挂起本身就是PCB的挂起)
V(sv):如果其他进程因为等待sv而被挂起,就让他恢复运行,如果没有进程因等待sv而被挂起,就给他加一。
(3)创建信号量:
key:唯一非零的整数,其他的进程可以通过key值来访问这个信号量,它代表程序可能使用的某个资源,程序对所有信号量的访问都是间接的。程序先通过调用segment函数并提供一个建,再由系统生成一个相应的信号标识符。只有segment函数才直接调用信号量键。
nsems:指定需要的信号量数目。
semflg:IPC_CREAT IPC_EXCL,如果只是单独使用IPC_CREAT则表示,如果这个有这个信号量,那么便使用这个信号量,如果这个信号量没有那么就创建一个。如果两个都是用,那么表示,如果这个信号量没有,则创建一个,如果有就会报错。
(4)改变信号量的值:
semid:semget函数返回的信号量标识符。
unsigned short sem_num:一般为0,除非有其他的信号量
short sem_op:由P操作和V操作返回的值,分别为+1,-1
short sem_flg:一般是SEM_UNDO
SEM_UNDO用于将修改的信号量值在进程正常退出或异常退出时归还给信号量
nsops:设置的信号量值
(5)控制信号量:
semid:semget函数返回的信号量标识符
sennum:设置信号量的值
cmd:它有四种值:IPC_STAT,IPC_SET,IPC_RMID,IPC_INFO
如果有第四个参数,那就是:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
(6)现在我们使用上面的函数来用信号量实现进程之间的通信:
1 #ifndef _COMM_H_
2 #define _COMM_H_
3 #include<stdio.h>
4 #include<sys/types.h>
5 #include<sys/ipc.h>
6 #include<sys/sem.h>
7 #include<string.h>
8 #include<stdlib.h>
9 #define PATHNAME "."
10 #define PROJ_ID 6666
11
12 union SemNo
13 {
14 int val;
15 struct semid_ds* buf;
16 unsigned short* array;
17 struct seminfo* _buf;
18 };
19
20 int CreateSemset(int nums);
21 int GetSemGet();
22 int InitSemSet(int semid,int num);
23 int P(int semid);
24 int V(int semid);
25 int DestorySet(int semid);
26 #endif
1 #include"comm.h"
2
3 int CommSemSet(int flags,int nums)
4 {
5 key_t _key=ftok(PATHNAME,PROJ_ID);
6 if(_key<0)
7 {
8 perror("ftok");
9 sleep(3);
10 return -1;
11 }
12 int semid=semget(_key,nums,flags);
13 if(semid<0)
14 {
15 perror("semget");
16 sleep(3);
17 return -2;
18 }
19 return semid;
20 }
21 int CreateSemSet(int nums)
22 {
23 return CommSemSet(IPC_CREAT|IPC_EXCL|0666,nums);
24 }
25 int GetSemSet()
26 {
27 return CommSemSet(0,0);
28 }
29 int InitSemSet(int semid,int nums)
30 {
31 union SemNo _sn;
32 _sn.val=1;
33 if(semctl(semid,nums,SETVAL,_sn)<0)
34 {
35 perror("semctl");
36 sleep(3);
37 return -1;
38 }
39 return 0;
40 }
41 int CommPV(int semid,int nums,int flags)
42 {
43 struct sembuf _s[1];
44 _s[0].sem_op=flags;
45 _s[0].sem_num=nums;
46 if(semop(semid,_s,1)<0)
47 {
48 perror("semop");
49 sleep(3);
50 return -1;
51 }
52 return 0;
53 }
54 int P(int semid)
55 {
56 return CommPV(semid,0,-1);
57 }
58 int V(int semid)
59 {
60 return CommPV(semid,0,1);
61 }
62 int DestorySemSet(int semid)
63 {
64 if(semctl(semid,0,IPC_RMID)<0)
65 {
66 perror("semctl");
67 sleep(3);
68 return -1;
69 }
70 return 0;
71
72 }
73
74 int main()
75 {
76 int semid=CreateSemSet(1);
77 InitSemSet(semid,0);
78 pid_t id=fork();
79 if(id==0)
80 {
81 int semdi=GetSemSet();
82 while(1)
83 {
84 P(semid);
85 printf("A");
86 fflush(stdout);
87 usleep(300000);
88 printf("a");
89 fflush(stdout);
90 usleep(300000);
91 V(semid);
92 }
93 }
94 else
95 {
96 while(1)
97 {
98 P(semid);
99 printf("B");
100 fflush(stdout);
101 usleep(300000);
102 printf("b");
103 fflush(stdout);
104 usleep(300000);
105 V(semid);
106 }
107 }
108 }
109
其运行结果为: