首页 > 代码库 > 信号量
信号量
信号量的主要目的是提供一种进程间同步的方式。
信号量有两种: 有名信号量和无名信号量。无名信号量也被称作基于内存的信号量。 有名信号量通过IPC名字进行进程间的同步,而无名信号量如果不是放在进程间的共享内存区中,是不能用来进行进程间同步的,只能用来进行线程间同步。
信号量有三种操作:
1. 创建一个信号量。创建的过程还要求初始化信号量的值。
根据信号量取值(代表可用资源的数目)的不同,POSIX信号量还可以分为:
- 二值信号量:信号量的值只有0和1,类似于互斥量,若资源被锁住,信号量的值为0,若资源可用,则信号量的值为1。
- 计数信号量:信号量的值在0到一个大于1的限制值(POSIX指出系统的最大限制值至少要为32767)。该计数表示可用资源的个数。
2. 等待一个信号量(wait)。该操作会检查信号量的值,如果其值小于或等于0,那就阻塞,直到该值变成大于0,然后等待进程将信号量的值减1,进程获得共享资源的访问权限。这整个操作必须是一个原子操作。该操作还经常被称为P操作(荷兰语Proberen,意为:尝试)。
3. 挂出一个信号(post)。该操作将信号量的值加1,如果有进程阻塞着等待该信号量,那么其中一个进程将被唤醒。该操作也必须是一个原子操作。该操作还经常被称为V操作(荷兰语Verhogen,意为:增加)。
信号量函数接口
1. 有名信号量的创建和删除
1 #include<semaphore.h>
2
3 sem_t *sem_open(const char *name, int oflag);
4 sem_t *sem_open(const char*name, int oflag, mode_t mode, unsigned int value); // 成功返回信号量指针,失败返回SEM_FAILED
sem_open用于创建或打开一个信号量,信号量是通过name参数即信号量的名字来进行标识的。
oflag参数可以为0,O_CREAT,O_EXCL。如果为0表示打开一个已存在的信号量,如果为O_CREAT表示如果信号量不存在就创建一个信号量,如果存在则打开并返回。此时mode和value需要指定。如果为O_CREAT|O_EXCL,表示如果信号量已存在会返回错误。
mode参数用于创建信号量时,表示信号量的权限位,和open函数一样包括:S_IRUSR, S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH, S_IWOTH。
value表示创建信号量时,信号量的初始值。
1 #include <semaphore.h>
2
3 int sem_close(sem_t *sem);
4 int sem_unlink(const char *name); // 成功返回0,失败返回-1
sem_close用于关闭打开的信号量。当一个进程终止时,内核对其上仍然打开的所有有名信号量自动执行这个操作。调用sem_close关闭信号量并没有把它从系统中删除它,有名信号量是随内核持续的。即使当前没有某个进程打开某个信号量它的值依然保持。直到内核重新自举或调用sem_unlink()删除该信号量。
sem_unlink用于将有名信号量立刻从系统中删除,但信号量的销毁是在所有进程都关闭信号量的时候。
2. 信号量的P操作
1 #include<semaphore.h>
2 int sem_wait(sem_t *sem);//成功返回0,失败返回-1
sem_wait()用于获取信号量,首先会测试指定信号量的值,如果大于0,就会将它减1并立即返回,如果等于0,那么调用线程会进入睡眠,指定信号量的值大于0。
3. 信号量的V操作
1 #include<semaphore.h>
2 int sem_post(sem_t *sem); //成功返回0,失败返回-1
当一个线程使用完某个信号量后,调用sem_post,使该信号量的值加1,如果有等待的线程,那么会唤醒等待的线程。
4. 获取当前信号量的值
1 #include<semaphore.h>
2 int sem_getvalue(sem_t *sem, int *sval); //成功返回0,失败返回-1
该函数返回当前信号量的值,通过sval输出参数返回,如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。
信号量