信号量是一种用于提供不同进程间或一个给定进程的不同线程件同步手段的原语.信号量是一个特殊的整数值,主要用来控制多个进程对临界资源的互斥访问,进程根据信号量来判断是否有 访问的资源。
信号量是一个计数器,可用于同步多进程对共享数据对象得访问,为了获得共享资源,进程需要执行以下操作:
1、测试控制该资源的信号量
2、若此信号量的值为正,则进程可以使用该资源,进程将信号量值减1,表示它使用了一个资源单位
3、若此信号量的值为0,则进程进入睡眠状态,直至信号量值大于0。当进程被唤醒后,它返回至第1步。
常用的信号量一般初始值为1,只控制单个资源,有时也称互斥锁,但是,信号量得初值可以是任意一正值,该值说明有多少个共享资源单位可供共享应用,信号量有以下3个特性:
1、信号量并非是一个非负值,而必须将信号量定义为含有一个或多个信号量值得集合,当创建一个信号量时,要指定该集合中的各个值。
sreuct sem
{
ushort_t semvl;
short sempid;
ushort semncnt;
ushort semzcnt;
};
2、创建信号量对其赋初值分开,这是一个致命弱点,因为不能原子地创建一个信号量集合,并且对该集合中的所有值赋初值。
3、即使没有进程使用,但他们仍然存在,因此必须考虑在进程终止时有没有释放得信号量。
以上的三个特性就导致了信号使用的复杂性。
信号量的值通过P、V原语来进行操作改变的。(p为减操作,v为加操作)
在Linux中,系统提供了信号量的操作函数,主要有以下函数:
1、key_t ftok(char *pathname, char proj);
根据参数pathname和proj 来创建一个关键字,成功时返回与路径pathname相对应的一个键值,具有唯一性,失败时返回值为-1.
2、int semget (key_t key, int nsems , int semflg);
创建一个新信号量或者取得一个现有的信号量,key是一个关键字,是用ftok()函数创建。nsems表明创建的信号量个数,semflg是设置信号量的访问权限标志,函数调用成功时返回信号量ID,失败则返回-1.
3、int semop (int semid, struct sembuf *spos, int nspos);
对信号量进行操作的函数,用于改变信号量的键值,semid是信号量的标志,spos是指向一个结构体数组的指针,表明要进行什么操作,nspos表明数组的元素个数,调用成功则返回0,失败则返回-1.
4、semctl(int semid , int semnum , int cmd , …/* union semun arg */);
semid是信号量标志,semnum是指该信号量集合内的某个成员(用下标表示0-nsems-1)。semnum只用于GETVAL、SETVAL、GETNCNT、GETZCNT、GETPID命令。参数cmd是可选的,它支持以下命令:
GETVAL:把semval的当前值返回。
SETVAL:设置senval值
GETPID:把当前sempid当作函数返回值
GETNCNT:把semncnt的当前值当作函数的返回值
GETZCNT:把semzcnt的当前值当作函数的返回值
IPC_RMID:把由sem_id指定的信号量从系统中删除
IPC_SET:设定指定信号量集合的semid_ds结构中的三个成员
IPC_STAT:返回所指定信号量当前的semid_ds结构
SETALL:设定所指定信号量集合中每个成员的semval值
GETALL:返回所指定信号量集合中每个成员的当前semval的值
Struct sembuf
{
Unsigned short sem_num; /*sem index in array*/
Short sem_op; /* sem operation */
Short sem_flg;/* operation flags */ sem_flg&IPC_RND 0
};
其中,如果sem_op大于0,那么操作值加入到信号量的值中,并唤醒等待信号增加的进程,如果sem_op为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0,如果sem_op小于0,函数判断信号量的值加上这个负值,如果结果为0唤醒等待信号量为0的进程,如果小于0函数阻塞,如果大于0,那么从信号量里面减去这个值并返回。
4、int semctl (int semid, int semnum, int cmd, union semun arg);
该函数得作用是对信号量进行一系列得控制,semid是要操作得信号量标志,semnum是信号量得下标,cmd是操作的命令,经常用的两个命令是&#