信号量(又称之为信号灯)与(管道、FIFO和消息队列)不同,它是一个计数器,用于多进程对共享数据对象的访问,保证关键代码段不被并发调用。
为了获得共享资源,进程需要进行如下操作:
(1)测试控制该资源的信号量。
(2)若此信号量的值为正,则进程可以使用该资源。进程将信号量值减一,表示它使用了一个资源单位。
(3)若此信号量的值为0,则进程进入休眠状态,直至信号量值大于0.进程被唤醒后,回到第一步开始。
信号量值的测试及减一操作应当是原子操作。信号量通常是在内核中实现的。信号量的值表示由多少个共享资源单位可以供享用。
相应的头文件:#include
#include
#include
1、创建信号量:#include
int semget(key_t key, int nsems, int flag);
成功:返回信号量集的IPC标识符。 失败:返回-1;
参数说明:
第一个参数:在本地系统中表示要创建或访问信号量的ID值,IPC_PRIVATE表示创建一个新的信号量;
第二个参数 nsems:表示该集合中的信号量。大于等于0;表示由可用资源数。
如果是创建新的信号量(一般是在服务器中进行),则必须指定nsems。如果引用一个现存的集合(一个客户进程),则将nsems指定为0;
第三个参数flag:指定选项和权限位的标志。IPC_CREAT和IPC_EXEL;
2、信号量的相关操作:
两个函数semop()和semctl():函数semop()用来操作一个信号量集,通过修改sem_ip指定对资源进行操作,而semctl()函数对信号量本身的值进行操作,可以修改信号量的值或者删除一个信号量。
-
int semop(int semid, struct sembuf semoparray[], size_t nops);
成功返回0,失败返回-1;
参数说明:
semid:通过semget()函数返回的一个信号量集标识符ID;
nops:标明参数semoparray所指向数组中的元素个数。
semoparray是一个结构数组指针。结构体struct sembuf用来说明要执行的操作。
struct sembuf{
unsigned short sem_num; //对应信号量集中的某个资源
short sem_op; //指明所要执行的操作
short sem_flg; //函数semop的行为
}
sem_num:其实相对应的信号量集合中的某个资源,它的值是从0到相对应信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。
sem_op:指明想要进行的操作。
sem_flag:说明函数semop的行为。
sem_op的值是一个整数:
(1)sem_op > 0 :释放相应的资源数,如果有两个信号量,释放信号量1,则其semval+1,对信号量这个无名结构体的操作,通过semctl函数来实现。
(2)sem_op == 0:进程阻塞直到信号量的相应值为0,档信号量已经为0,函数立即返回。
(3)sem_op < 0:请求sem_op的绝对值的资源数。
sem_flag:
该参数可以设置成为IPC_NOWAIT和SEM_UNDO两种状态。
IPC_NOWAIT:对信号的操作不能满足时,semop()不会阻塞,并立即返回,同事设定错误信息。
IPC_UNDO:程序结束时释放信号量,这样做可以避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
int semctl(int sem_id, int semnum, int cmd[, union semun arg]);
参数说明:
sem_id:信号量集标识符;
semnum:指定信号量集中某一个信号灯成员,其值在(0~nsems-1);
cmd:定义了函数要进行的操作;
cmd的常用值:
IPC_STAT:对此集合区semid_ds结构,并不存放在arg.buf之中。
GETVAL:返回结构体数组中以semnum为下标的元素的成员semval值。
SETVAL:使用arg.val对该信号量的semnum.sempid赋值
第四个参数是可选的,但是其很重要不能忽略,它的类型是semun,它是多个特定命令的联合(union):
union semun {
int val; //val的值为cmd命令的SETVAL所用;
struct semid_ds *duf;
unsigned short *array;
}
信号量在使用之前必须进行初始化,初始化的方式为:
-
union semum sem_arg; //定义联合变量;
-
sem_arg.val = 1;
-
int rec;
-
rec = semctl(semid,0,SETVAL,sem_arg);
-
if(rec == -1)
-
{
-
perror("init\n");
-
}
在使用信号量的时候这个联合应先定义在代码的开头。