信号量是一种编程概念,经常用于解决多线程问题。我对社区的问题是:

什么是信号量,如何使用它?


当前回答

Michael Barr的文章《互斥量和信号量揭秘》很好地介绍了互斥量和信号量的不同之处,以及什么时候应该和不应该使用它们。我在这里摘录了几个关键段落。

关键在于应该使用互斥来保护共享资源,而应该使用信号量来发送信号。通常不应该使用信号量来保护共享资源,也不应该使用互斥量来发送信号。例如,在使用信号量来保护共享资源方面,使用bouncer类比是有问题的——您可以这样使用它们,但这可能会导致难以诊断错误。

While mutexes and semaphores have some similarities in their implementation, they should always be used differently. The most common (but nonetheless incorrect) answer to the question posed at the top is that mutexes and semaphores are very similar, with the only significant difference being that semaphores can count higher than one. Nearly all engineers seem to properly understand that a mutex is a binary flag used to protect a shared resource by ensuring mutual exclusion inside critical sections of code. But when asked to expand on how to use a "counting semaphore," most engineers—varying only in their degree of confidence—express some flavor of the textbook opinion that these are used to protect several equivalent resources.

...

在这一点上,一个有趣的类比是使用浴室钥匙的想法来保护共享资源-浴室。如果一家商店只有一间浴室,那么一把钥匙就足以保护这一资源,防止多人同时使用。

如果有多个浴室,人们可能会试图用相同的键来设置多个键——这类似于误用信号量。一旦你有了一个键,你实际上不知道哪个浴室是可用的,如果你沿着这条路走下去,你可能最终会使用互斥锁来提供该信息,并确保你没有使用已经被占用的浴室。

A semaphore is the wrong tool to protect several of the essentially same resource, but this is how many people think of it and use it. The bouncer analogy is distinctly different - there aren't several of the same type of resource, instead there is one resource which can accept multiple simultaneous users. I suppose a semaphore can be used in such situations, but rarely are there real-world situations where the analogy actually holds - it's more often that there are several of the same type, but still individual resources, like the bathrooms, which cannot be used this way.

...

The correct use of a semaphore is for signaling from one task to another. A mutex is meant to be taken and released, always in that order, by each task that uses the shared resource it protects. By contrast, tasks that use semaphores either signal or wait—not both. For example, Task 1 may contain code to post (i.e., signal or increment) a particular semaphore when the "power" button is pressed and Task 2, which wakes the display, pends on that same semaphore. In this scenario, one task is the producer of the event signal; the other the consumer.

...

Here an important point is made that mutexes interfere with real time operating systems in a bad way, causing priority inversion where a less important task may be executed before a more important task because of resource sharing. In short, this happens when a lower priority task uses a mutex to grab a resource, A, then tries to grab B, but is paused because B is unavailable. While it's waiting, a higher priority task comes along and needs A, but it's already tied up, and by a process that isn't even running because it's waiting for B. There are many ways to resolve this, but it most often is fixed by altering the mutex and task manager. The mutex is much more complex in these cases than a binary semaphore, and using a semaphore in such an instance will cause priority inversions because the task manager is unaware of the priority inversion and cannot act to correct it.

...

The cause of the widespread modern confusion between mutexes and semaphores is historical, as it dates all the way back to the 1974 invention of the Semaphore (capital "S", in this article) by Djikstra. Prior to that date, none of the interrupt-safe task synchronization and signaling mechanisms known to computer scientists was efficiently scalable for use by more than two tasks. Dijkstra's revolutionary, safe-and-scalable Semaphore was applied in both critical section protection and signaling. And thus the confusion began. However, it later became obvious to operating system developers, after the appearance of the priority-based preemptive RTOS (e.g., VRTX, ca. 1980), publication of academic papers establishing RMA and the problems caused by priority inversion, and a paper on priority inheritance protocols in 1990, 3 it became apparent that mutexes must be more than just semaphores with a binary counter.

互斥:资源共享

信号:信号

在没有仔细考虑副作用的情况下,不要用一种药物来替代另一种药物。

其他回答

假设一辆出租车可以容纳3人(后面)+2人(前面),包括司机。因此,一个信号量一次只允许5个人在一辆车里。 互斥只允许一个人坐在汽车的一个座位上。

因此,互斥量是允许对资源的独占访问(如操作系统线程),而信号量是允许在同一时间访问n个资源。

信号量是一个包含自然数(即大于或等于零的整数)的对象,在自然数上定义了两个修改操作。一个运算V,给自然数加1。另一个操作,P,将自然数减少1。这两个活动都是原子的(即没有其他操作可以与V或P同时执行)。

因为自然数0不能减少,所以在包含0的信号量上调用P将阻塞调用进程(/thread)的执行,直到该数字不再为0,P可以成功(原子地)执行为止。

正如在其他回答中提到的,信号量可用于将对某个资源的访问限制为最大(但可变的)进程数。

@Craig:

信号量是一种锁定 资源,这样才有保证 当执行一段代码时, 只有这段代码可以访问 该资源。这保留了两个线程 从并发访问资源, 这可能会导致问题。

这不仅仅局限于一个线程。信号量可以配置为允许固定数量的线程访问资源。

想象一下,每个人都想上厕所而浴室的钥匙是有限的。如果剩下的钥匙不够多,那个人就需要等待。因此,可以将信号量看作是表示不同进程(上厕所的人)可以请求访问的卫生间(系统资源)可用的一组键。

现在想象一下两个过程同时去洗手间。这不是一个好的情况,信号量被用来防止这种情况。不幸的是,信号量是一种自愿机制,进程(我们的上厕所的人)可以忽略它(即,即使有钥匙,有人仍然可以把门踢开)。

二进制/互斥量和计数信号量之间也有区别。

请登录http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html查看课堂讲稿。

信号量是一种锁定资源的方法,以保证在执行一段代码时,只有这段代码可以访问该资源。这可以防止两个线程并发访问一个资源,从而导致问题。