进程与线程
信号变量(Semaphores)
现在把场景从卫生间转移到厨房,同一时间在厨房里面有几个人是可以接受的。在厨房里面,你也可能不想让所有的人同时进入。实际上,你可能是想让厨房中的人数保持在你设定的限度之内。
比如你不想在任何时间点厨房中的人数超过两个。这可以使用互斥体来实现么?根据我们的定义,是不行的。为什么不行就是我们的比喻中的一个非常有趣的问题。
计数为1的信号变量
卫生间可能遇到的情况是以下两种情况之一,有两种状态是互相关联的:
- 门是开的并且无人在房间内
- 门被锁住并且有一个人在房间内
至于其他的组合是不存在的——房间内没人门是不会被锁住的(如果这样的话,我们该如何打开这个门呢?),而有人在房间里面门也是不能被打开的(如果打开的话,如何保证他们的隐私?)。这就是计数为一的信号变量的例子——在那个房间里面最多只能有一个人,或是一个线程在使用这个信号变量。
这里的关键就是我们描绘这个锁的方式。对于常见的卫生间门锁,你可以在内部开关这个锁——不存在可以在外部开锁的钥匙。实际上,互斥体的拥有是一个元素级的操作——当你正在执行获取互斥体的操作的时候,别的线程是没有机会获取它的,而产生有两个线程同时拥有互斥体的情况。在我们的这个房子的比喻中,这不是那么明显,因为人类比1与0要聪明多了。
我们举厨房的例子是要说明另一类不同的锁。
计数大于1的信号变量
假设我们在厨房安装了传统的需要钥匙开启的锁。这种锁的工作方式如下,如果你有一把对应的钥匙,你就可以打开这把锁并进入厨房里面。使用这个锁的所有人都同意当他们进入厨房之后就立刻从内部锁上这个门,这样外面的人必须在有钥匙的情况下才能进入厨房。
于是,控制厨房中的人数就变得很简单了——在门外挂两把钥匙,并且厨房永远是锁住的。如果有人想进入厨房的话,就先看看门外是否有一把挂着的钥匙。如果有的话,他们就可以拿到那把钥匙,打开厨房的门,进入厨房并使用这把钥匙锁门。
由于进入厨房的人必须带着他们的钥匙,我们就能够通过控制厨房门外的钥匙的数量,来控制在厨房中允许进入的人数。
对于线程来说,完成这个功能的就是信号变量(semaphore)。简单的信号变量的工作方式和互斥体是几乎一样的——你要么拥有互斥体从而可以访问资源,要么就不拥有互斥体从而不能访问资源。我们刚刚描述的信号变量是计数信号变量(counting semaphore)——它一直保持计数(就是线程可用的钥匙的数量)。
信号变量作为互斥体使用
我们刚刚问了个问题,就是能否使用互斥体来实现有计数功能的锁。对这个问题的答案是不能。是否还有其他的方式来完成该目的?另外能否将信号变量作为互斥体使用?
是的。在一些操作系统中,它们实际上就是这样做的——它们没有互斥体,只有信号变量!也就没有让互斥体造成困扰的必要了。
要回答这个问题,请想一下你的房子的洗手间。盖房子的人如何来实现“互斥体”?我想你应该没有一把钥匙挂在墙上吧。
互斥体是一种特定用途的信号变量。如果你想让一个线程运行特定段代码,互斥体就是目前为止最有效的实现方式。
后面要提到的其他同步策略,包括了叫做条件变量、屏障以及睡眠量的东西。
Related posts:
最近评论