一.本质
信号量就是一个计数器,用来计算可以资源的个数。也是一个等待队列,保存的是PCB指针。它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。
二.作用
信号量主要用于进程的同步和互斥。
互斥:由于各个进程间要访问共享资源,而这些资源需要排他使用,因此各个进程之间要竞争使用这些资源,我们将这种关系称为进程互斥。系统中某些资源一次只允许一个进程使用,称这些资源为临界资源或互斥资源。在进程中涉及到互斥资源的程序段叫临界区。例子:电影院购买电影票
同步:多个进程需要相互配合才能完成一项任务。例子:公交车和售票员的关系
三.基本操作
PV操作
信号量:互斥:PV在同一进程中 同步:PV在不同的进程中
信号量的值:S>0:S表示可用资源的个数 S=0:表示无可用资源,无等待进程 S<0:|S|表示等待队列中进程的个数。
四.PV原语
P-->申请资源
V--->释放资源
四.API
1.创建和访问一个信号量集
1)头文件:#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
2)函数原型:int semget(key_t key, int nsems, int semflg);
3)函数参数:key 信号集名字 nsems 信号集中信号量的个数 semflg 权限标志,和创建文件时一样
4)返回值:成功返回信号集的标识码,失败返回-1
2.控制信号集
1)头文件:和创建头文件相同
2)函数原型:int semctl(int semid, int semnum, int cmd, ...);
3)函数参数:semid 有创建函数返回的信号集标识码 semnum 信号集中信号量的序号 cmd将要执行的操作
最后一个参数是联合体,一般自己定义,传地址
4)返回值:成功返回0,失败返回-1
5)cmd参数的几种情况:SETVAL设置信号量集中的信号量的计数值
GETVAL获取信号量集中的信号量的计数值
IPC_STAT 把semid_ds结构中的数据设置为信号集的当前关联值
IPC_SET在进程有足够权限的前提下,把信号集的当前关联值设置为semid_ds数据结构中给出的值
IPC_RMID删除信号集
3.PV操作
1)头文件:和创建头文件相同
2)函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
3)函数参数:semid 信号集标识码 sops 指向结构体的指针 nsops信号量的个数
4)返回值:成功返回0;失败返回-1
5)sembuf结构体
五.举个例子
//comm.c
1 #include "comm.h"
2
3 int Createsem(int flag){
4 int key=ftok(PATHNAME,FILENAME);
5 int sem=semget(key,NUM,flag);
6 if(sem==-1){
7 perror("semget");
8 return -1;
9 }
10 return sem;
11 }
12
13 int initsem(int sem,int value){
14 union semun num;
15 num.val=value;
16 int init =semctl(sem,0,SETVAL,num);
17 if(init==-1){
18 perror("semctl");
19 return -1;
20 }
21 return 1;
22 }
23
24 void destorysem(int sem){
25 int des=semctl(sem,0,IPC_RMID);
26 if(des==-1){
27 perror("semctl");
28 }
29 }
30
31 int handle(int sem,int _sem_num,int op){
32 struct sembuf buf;
33 buf.sem_num=_sem_num;
34 buf.sem_op=op;
35 buf.sem_flg=0;
36
37 int sep=semop(sem,&buf,1);
38 if(sep==-1){
39 perror("semop");
40 return -1;
41 }
42 return 1;
43 }
44
45 int P(int sem,int who){
46 return handle(sem,who,-1);
47 }
48
49 int V(int sem,int who){
50 return handle(sem,who,1);
51 }
//comm.h
1 #include <sys/sem.h>
2 #include <sys/types.h>
3 #include <sys/ipc.h>
4 #include <unistd.h>
5 union semun{
6 int val;
7 struct semid_ds *buf;
8 unsigned short *array;
9 struct seminfo *__buf;
10 };
11
12 #define PATHNAME "."
13 #define FILENAME 0x008
14 #define NUM 1
15
16 int Createsem(int flag);
17 int initsem(int sem,int value);
18 void destorysem(int sem);
19 int handle(int sem,int _sem_num,int op);
20 int P(int sem,int who);
21 int V(int sem,int who);
22
//fork.c
1 #include "comm.h"
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <wait.h>
5 #include <sys/types.h>
6 int main(void){
7 pid_t pid=fork();
8 int sem=Createsem(IPC_CREAT|0644);
9 initsem(sem,1);
10 if(pid==0){
11 int _sem=Createsem(0);
12
13 while(1){
14 P(_sem,0);
15 printf("C");
16 fflush(stdout);
17 printf("C ");
18 fflush(stdout);
19 usleep(20000);
20 V(_sem,0);
21 }
22 }else if(pid>0){
23 while(1){
24 P(sem,0);
25 printf("F");
26 fflush(stdout);
27 printf("F ");
28 fflush(stdout);
29 usleep(20000);
30 V(sem,0);
31 }
32 wait(NULL);
33 }
34 destorysem(sem);
35 return 0;
36 }
运行结果