信号量的概念
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。如果sem_trywait在信号量为零时执行wait操作,则将errno置为EAGAIN。
sem_post,sem_wait和sem_trywait同样可用于命名信号量。
信号量的实例
下面是一个无名信号量的应用实例,它完成的工作为:创建两个线程,这两个线程各自将自己的一个整型变量i从1递增到100,并通过信号量控制递增的过程,即这两个整型变量的差不能超过5。

本文介绍了信号量的概念,作为操作系统中的互斥和同步机制。详细阐述了POSIX无名信号量的使用,包括初始化、销毁、signal和wait操作。同时提供了一个实例,展示如何利用信号量确保两个线程在递增变量时保持差值不超过5。
最低0.47元/天 解锁文章
496

被折叠的 条评论
为什么被折叠?



