为什么信号量?

时间:2010-11-16 16:28:30

标签: operating-system ipc semaphore

为什么在使用简单变量实现相同功能时使用二进制信号量?

7 个答案:

答案 0 :(得分:6)

因为信号量不是一个简单的变量,所以它是一个比它更大的构造。

具体来说,对于计数信号量(二进制信号量实际上是1的计数),可以阻止任何尝试将信号量增加到其最大值以上的进程/线程。

信号量也有额外的功能,它们的状态是“原子地”改变的,这意味着底层存储器被逻辑包围,以确保CPU缓存等被刷新,并且当值被改变时,它被改变为“大家”。这在现代多核处理器上尤为重要。

当您尝试防止共享资源过度使用时,信号量适合使用。二进制信号量非常适合一次只能由一个进程/线程使用的资源。

答案 1 :(得分:3)

因为变量不能跨进程工作。系统信号量确实如此。

答案 2 :(得分:3)

有很多原因。因为信号量是由操作系统提供的,所以它可以......

a)在多个流程之间共享。

b)用于阻止等待过程,而不是忙着等待。

c)实际工作。由多个线程共享的变量,或者在多个进程的共享内存空间中共享的变量,不会为您提供信号量的安全性,因为您永远不知道您的线程/进程何时会失去控制。当您获得二进制信号量时,您知道您是该代码部分中唯一的线程/进程,操作系统保证这一点。

我建议你读一本关于此的书,这是一个愚蠢的问题:)没有冒犯!

答案 3 :(得分:1)

信号量原子操作对于多线程代码至关重要,否则将无法确定哪个线程首先出现。例如,如果您有两个处理电子邮件请求的线程,并且您希望每个人只收到一封电子邮件;您需要确定是否已处理电子邮件请求。如果没有信号量,会发生什么:

Thread A checks if email[0] has been read, it has not
Thread B checks if email[0] has been read, it has not
Thread A sends email[0] and marks it as done
Thread B sends email[0] and marks it as done

对于用户,电子邮件已被发送两次,因为两个线程都将其视为未处理。现在有一个信号量,这是电子邮件发生的事情:

Thread A marks email[0] as in progress via a semaphore
Thread B checks email[0] and sees the semaphore is marked
Thread A sends email[0] and marks it as done then unmarks the semaphore

使用信号量只有一个线程会处理电子邮件。

答案 4 :(得分:1)

实际上,信号量并不像一个变量。如上所述,它具有许多优点。你可以阅读这本书,“The Semaphores的小书,第2版,作者:Allen B. Downey”,了解有关信号量的更多细节。

答案 5 :(得分:0)

信号量限制跨进程的访问,而变量(即使是应用程序的全局变量)也不能在系统范围内执行相同的操作。

此外,为什么重新发明轮子?您必须使用变量自己处理所有实现,而使用信号量,操作系统已经提供了该功能,并保证可以正常工作。

答案 6 :(得分:0)

让我们假设一种实现资源保护的简单方法可以通过使用变量即BOOLEAN来完成。我举个例子:

while {resource_protected == TRUE}
{
// resource is protected
}

现在我们可以通过设置resource_protected == TRUE来保护资源。

要检查资源是否可用,我们只需使用以下内容:

if {resource_protected == FALSE}
{    // <---- rescheduling possible here!
resource_protected == TRUE; // protect resource
}
else
{
//try again later
}

但这种方法存在两个问题。首先,这会创建一个忙等待,因此处理器不能自由地做其他事情。其次,更重要的是,这个活动进程可以重新安排(移动到等待队列)检查BOOLEAN之后但是之前它通过将BOOLEAN设置为TRUE来保护资源为资源仍然免费的其他进程创建幻觉,因为BOOLEAN尚未设置。这允许其他进程声明资源。现在活动的进程(从等待队列升级到由于重新安排而运行)通过将BOOLEAN设置为TRUE来保护资源(因为它尚未由等待队列中的重新安排的进程设置)。现在重新安排此活动进程,并且先前的进程再次变为活动状态,它将BOOLEAN设置为TRUE(尽管第二个进程已将其设置为TRUE),因为它已经检查了BOOLEAN。现在这两个进程声明了相同的资源,你将会死去一个试图调试这个混乱的老人。

使用信号量可以避免这种难看的丑陋混乱,因为它允许原子。原子是从其他过程的角度出现不可分割的指令集。因此,通过糟糕的重新安排来避免这种不幸事件。