1.概述
信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常被用做一个锁机制。
2.相关数据结构与函数
信号量数据结构:
structsemun
{
intval;//当执行SETVAL命令时,用于指定要把信号量设置成什么值。
structsemid_ds *buf;//当执行命令IPC_STAT/IPC_SET,代表内核中所使用的内部信号量数据结构的一个复制。
unsignedshrot *array;//用在GETALL/SETALL命令中的一个指针。
structseminfo *__buf; //信号量内部结构,内部使用,Linux操作系统特有的。
};
新建信号量函数semget(),原型如下:
intsemget(key_t key, int nsems, int semflg);
semflg是打开信号的方式:
-
IPC_CREAT:如果内核不存在这样的信号量集合,则把它创建出来。
-
IPC_EXCL:与IPC_CREAT一起使用,当信号量存在时,则出错。
-
信号量操作函数semop(),原型如下:
intsemop(int semid, struct sembuf *sops, unsigned nsops);
其中,sembuf的定义如下:
structsembuf
{
ushortsem_num; //信号量的编号
shortsem_op; //信号量的操作
shortsem_flg; //信号量的操作标志
};
控制信号量参数semctl()
intsemctl(int semid, int semnum, int cmd, …);
cmd的取值如下:
-
IPC_STAT: 获取某个集合的semid_ds结构,并把它存储在semun联合体的buf参数所指定的地址
-
IPC_SET: 设置某个集合的semid_ds结构的ipc_perm成员的值。该命令所取的值是从sumun联合体的buf参数中取到的。
-
IPC_RMID: 从内核中删除该集合。
-
GETALL: 用于获取集合中所有信号量的值。
-
GETNCNT: 返回当前正在等待资源的进程的数目。
-
GETPID: 返回最后一次执行semop调用的进程的PID。
-
GETVAL: 返回集合中某个信号量的值。
-
GETZCNT: 返回正在等待资源利用率达到百分之百的进程数目。
-
SETALL: 把集合中所有信号量的值设置为联合体的array成员所包含的对应值。
-
SETVAL: 把集合中的单个信号量的值设置为联合体的val成员的值。
-
参数arg代表类型semun的一个实例。
3.实例
/*-------------------信号量操作实例------------------------------*/
#include<stdio.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
typedefint sem_t;
unionsemun
{
intval;
structsemid_ds *buf;
unsignedshort *array;
}arg;
/*创建信号量*/
sem_tCreateSem(key_t key, int value)
{
unionsemun sem;
sem_tsemid;
sem.val= value;
semid= semget(key, 0, IPC_CREAT | 0666);
if(-1 == semid)
{
printf("createsemaphore error\n");
return-1;
}
semctl(semid,0, SETVAL, sem);
returnsemid;
}
/*增加信号量*/
intSem_P(sem_t semid)
{
structsembuf sops = {0, +1, IPC_NOWAIT};
return(semop(semid, &sops, 1));
}
/*减小信号量*/
intSem_V(sem_t semid)
{
structsembuf sops = {0, -1, IPC_NOWAIT};
return(semop(semid, &sops, 1));
}
/*设置信号量的值*/
voidSetvalueSem(sem_t semid, int value)
{
unionsemun sem;
sem.val= value;
semctl(semid,0, SETVAL, sem);
}
/*获取信号量的值*/
intGetvalueSem(sem_t semid)
{
unionsemun sem;
returnsemctl(semid, 0, GETVAL, sem);
}
/*销毁信号量*/
voidDestroySem(sem_t semid)
{
unionsemun sem;
sem.val= 0;
semctl(semid,0, IPC_RMID, sem);
}
intmain(int argc, char *argv[])
{
key_tkey;
intsemid;
chari;
structsemid_ds buf;
intvalue = 0;
key= ftok("/ipc/sem", 'a');
semid= CreateSem(key, 100);
for(i= 0; i <= 3; i++)
{
Sem_P(semid);
Sem_V(semid);
}
value= GetvalueSem(semid);
printf("信号量值为:%d\n",value);
DestroySem(semid);
return0;
}