操作系统中的信号量在解决线程之间的同步中起着非常大的作用,那么什么是信号量呢?
百度百科:信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。
*:信号量(英语:Semaphore)又称为信号量、旗语,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态.
其中,信号量又分为两种:二进制信号量和计数信号量。
信号量的概念是由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger W. Dijkstra)发明的,广泛的应用于不同的操作系统中。在系统中,给予每一个进程一个信号量,代表每个进程目前的状态,未得到控制权的进程会在特定地方被强迫停下来,等待可以继续进行的信号到来。如果信号量是一个任意的整数,通常被称为计数信号量(Counting semaphore),或一般信号量(general semaphore);如果信号量只有二进制的0或1,称为二进制信号量(binary semaphore)。在linux系统中,二进制信号量(binary semaphore)又称互斥锁(Mutex)。
其中,信号量又存在着两种操作,分别为V操作与P操作,V操作会增加信号量 S的数值,P操作会减少它。
具体的运作方式如下:
- 初始化,给与它一个非负数的整数值。
- 运行 P(wait()),信号量S的值将被减少。企图进入临界区块的进程,需要先运行 P(wait())。当信号量S减为负值时,进程会被挡住,不能继续;当信号量S不为负值时,进程可以获准进入临界区块。
- 运行 V(又称signal()),信号量S的值会被增加。结束离开临界区块的进程,将会运行 V(又称signal())。当信号量S不为负值时,先前被挡住的其他进程,将可获准进入临界区块。
以上是*对于信号量的具体解释,下面是我自己对于信号量的一个理解。
信号量实际上就是一个值,这个值被用来解决临界区问题以及实现进程在多处理器环境下的进程同步。
其中,两个最重要的信号量为二进制信号量和计数信号量,计数信号量可以表示为非负的整数而二进制信号量只存在0和1两个值。
现在让我们看一下他们是怎样工作的吧。
首先,让我们看一下这两个可以读取以及改变信号量值的操作。
其中,p,v,操作接受一个共同的senaphore(信号量)作为参数,执行p操作时,当信号量s为0时,进行等待操作,此时进程被挂起。直到s的值不为0时,即s=1时,进程进入临界区,信号量值减1。当执行v操作时,进程执行完任务,从临界区出来,信号量s的值增加1。
一些关于P,V操作的关键点:
1.p操作也叫做wait操作,sleep操作或者down操作,而v操作也被叫做signal操作,wake-up以及up操作。
2.这两个操作都是原子化的并且信号量总是被初始化为1。
3.一个临界区总是被这一对p,v操作所包围从而去实现进程的同步。看下面这张图片,进程p的临界区在p操作与v操作之间。
现在,让我们看看信号量是怎样实现多进程共同的排斥效应。下面有2个进程p1进程和p2进程以及一个被初始化值为1的信号量s。现在我们假设p1进入了临界区导致信号量s的值变成了0,之后如果p2进程想进入临界区必须等到信号量s>0,这种情况只发生在当p1进程完成了在临界区需要执行的操作后对共同的信号量执行v操作,使得s的值由0增加1变为1,从p2进程可以结束等待,成功进入临界区执行操作。这种方法成功实现了多进程的同步,让我们看下面这张图来具体的分析一下。
上面描述的是一个值只能为0或者1的二进制信号量,另外还有一种其它的叫做计数信号量的信号量,它可以表示的值得数量超过1。现在假设有一个含有4个进程的资源队列,现在我们初始化信号量s的值为4,剩下的操作和二进制信号量一样。无论何时,进程想要使用资源需要调用p操作或者wait操作,当进程使用完资源需要调用v操作或者signal操作。如果s变为0则则进程不得不执行wait等待操作直到信号量s的值变为正数。举个栗子,假设有p1,p2,p3,p4四个进程并且它们都对信号量s执行了v操作(信号量s的值初始化为4),如果另一个进程p5想要进入临界区想要使用资源,它需要等到p1,p2,p3,p4这四个进程中的任意一个执行v操作使得信号量s的值变为正数。
实现信号量中存在的一些问题:
无论何时,进程在等待的过程中持续不断的去检查信号量的值(在p操作中看到while(s==0)这一语句),并且浪费cpu的周期,为了避免这种情况的发生,下面提供了一种更好的解决思路:
在这种实现方法中,无论什么时候,如果进程执行p操作,这个进程都会被添加进一个与信号量相关的进程等待队列,这是通过操作系统中叫做block()的方法实现进程的入队操作的,当一个进程完成资源的使用后,它调用v操作,并调用系统方法wakeup( ),接着等待队列中的一个进程重新开始进入临界区使用资源......
参考资料:
【1】*-信号量
【2】 https://www.geeksforgeeks.org/semaphores-operating-system by Ashish Sharma 翻译:刘扬俊