信号量

信号量的主要目的是提供一种进程间同步的方式。

信号量有两种: 有名信号量和无名信号量。无名信号量也被称作基于内存的信号量。 有名信号量通过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。

sem_wait() decrements(locks) the semaphore pointed to by sem. If the semaphore's value is greater than zero, then the decrement proceeds, and the function returns, immediately. If the semaphore currently has  the value zero, then the call blocks until either it becomes possible to perform the decrement(i.e., the semaphore value rises above zero), or a signal handler interrupts the call.

 

3. 信号量的V操作

1 #include<semaphore.h>
2 int sem_post(sem_t *sem); //成功返回0,失败返回-1

 当一个线程使用完某个信号量后,调用sem_post,使该信号量的值加1,如果有等待的线程,那么会唤醒等待的线程。

sem_post() increments(unlocks) the semaphore pointed to by sem. If the semaphore's value  consequently becomes greater than zero, then another process or thread blocked in a sem_wait() call will be woken up and proceed to lock the semaphore.

4. 获取当前信号量的值

1 #include<semaphore.h>
2 int sem_getvalue(sem_t *sem, int *sval); //成功返回0,失败返回-1

该函数返回当前信号量的值,通过sval输出参数返回,如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。

原文地址:https://www.cnblogs.com/zengtx/p/6376066.html