信号量的概念
1965年,E.W.Dijkstra提出了信号量的概念,之后信号量即成为操作系统实现互斥和同步的一种普遍机制。信号量是包含一个非负整型变量,并且带有两个原子操作wait和signal。wait还可以被称为down、P或lock,signal还可以被称为up、V、unlock或post。
如果信号量的非负整形变量S大于零,wait就将其减1,如果S等于0,wait就将调用线程挂起。对于signal操作,如果有线程在信号量上阻塞(此时S等于0),signal就会解除对某个等待线程的阻塞,使其从wait中返回,如果没有线程阻塞在信号量上,signal就将S加1。
由此可见,S可以被理解为一种资源的数量,信号量即是通过控制这种资源的分配来实现互斥和同步的。如果把S设为1,信号量即可实现互斥量的功能。如果S的值大于1,那么信号量即可使多个线程并发运行。
POSIX信号量是一个sem_t类型的变量,但POSIX有两种信号量的实现机制:无名信号量和命名信号量。无名信号量可以用在共享内存的情况下,比如实现进程中各个线程之间的互斥和同步。命名信号量通常用于不共享内存的情况下,比如不共享内存的进程之间。
信号量相关的函数和数据结构需要引用头文件semaphore.h。
POSIX无名信号量
在使用信号量之前,必须对其进行初始化。sem_init函数初始化指定的信号量,它的形式为:
int sem_init(sem_t *sem, int pshared, unsigned value);
参数sem指向要初始化的信号量,参数value为信号量的初始值。参数pshared用于说明信号量的共享范围,如果pshared为0,那么该信号量只能由初始化这个信号量的进程中的线程使用,如果pshared非零,任何可以访问到这个信号量的进程都可以使用这个信号量。如果成功,sem_init返回0,如果不成功,sem_init返回-1并设置errno。
函数sem_destroy销毁一个指定的信号量,它的形式为:
int sem_destroy(sem_t *sem);
参数sem为指向要销毁的信号量的指针。如果成功,sem_destroy返回0,如果不成功,sem_destroy返回-1并设置errno。如果*sem不是有效的信号量,sem_destroy就将errno置为EINVAL。
sem_post函数实现对指定信号量的signal操作,它的形式为:
int sem_post(sem_t *sem);
如果成功,sem_post返回0。如果不成功,sem_post返回-1并设置errno。如果*sem不是有效的信号量,sem_post就将errno置为EINVAL。
sem_wait函数实现对指定信号量的wait操作。sem_trywait函数与sem_wait类似,只是在试图对一个为零的信号量进行操作时,它不会阻塞调用线程,而是立即返回,类似于互斥量操作中的pthread_mutex_trylock()。这两个函数的形式为:
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
如果成功,这两个函数返回0,如果不成功,这些函数返回-1并设置errno。如果*sem不是有效的信号量,sem_ wait就将errno置为EINVAL