7

在阅读二进制信号量和互斥量时,我发现了以下区别:

两者都可以有值 0 和 1,但互斥锁可以由获得互斥锁的同一个线程解锁。如果更高优先级的进程想要获取相同的互斥锁,则获取互斥锁的线程可以进行优先级反转,而二进制信号量则不是这种情况。

那么我应该在哪里使用二进制信号量呢?谁能举个例子?

编辑:我想我已经弄清楚了两者的工作原理。基本上二进制信号量提供同步,而互斥量提供锁定机制。我阅读了 Galvin OS 书中的一些示例,以使其更加清晰。

4

3 回答 3

6

我发现二进制信号量非常有用的一种典型情况是线程初始化,其中线程将从父线程拥有的结构中读取。父线程需要等待新线程从结构中读取共享数据,然后才能让结构的生命周期结束(例如,通过离开其范围)。使用二进制信号量,您所要做的就是将信号量值初始化为零并让子级在父级等待它时发布它。如果没有信号量,您将需要一个互斥量和条件变量以及更丑陋的程序逻辑来使用它们。

于 2012-07-17T18:04:50.097 回答
3

在几乎所有情况下,我都使用二进制信号量来向其他线程发出信号而无需锁定。

同步请求的简单使用示例:

线程 1

Semaphore sem;
request_to_thread2(&sem); // Function sending request to thread2 in any fashion
sem.wait();               // Waiting request complete

线程 2

Semaphore *sem;
process_request(sem);     // Process request from thread 1
sem->post();              // Signal thread 1 that request is completed

注意:在线程 2 处理中发布信号量之前,您可以安全地设置线程 1 数据,而无需任何额外的同步。

于 2012-07-17T20:31:23.110 回答
1

使用计数信号量而不是二进制互斥锁的典型示例是,当您的可用资源数量有限时,a) 可互换且 b) 不止一个。

例如,如果您希望最多允许 10 个读者一次访问数据库,您可以使用初始化为 10 的计数信号量来限制对资源的访问。每个读取器必须在访问资源之前获取信号量,从而减少可用计数。一旦计数达到 0(即 10 个读者已获得访问权限并仍在使用数据库),所有其他读者将被锁定。一旦读者完成,他们将信号量计数增加一以表明他们不再使用该资源,并且其他一些读者现在可以获得信号量锁并获得访问权。

然而,计数信号量,就像所有其他同步原语一样,有很多用例,这只是一个跳出框框思考的问题。您可能会发现,您习惯使用互斥锁和附加逻辑解决的许多问题都可以使用信号量更轻松、更直接地实现。互斥量是信号量的一个子集,也就是说,你可以用互斥量做的任何事情都可以用一个信号量来完成(只需将计数设置为 1),但是有些事情可以单独用一个信号量来完成不能只用一个互斥锁来完成。

归根结底,任何一个同步原语通常都足以做任何事情(将其视为线程同步的“图灵完备”,将这个词混为一谈)。然而,每一个都是为不同的应用程序量身定做的,虽然你可以通过一些定制和额外的粘合来强迫一个人做你的竞标,但不同的同步原语可能更适合这项工作。

于 2012-07-17T18:11:09.393 回答