什么是信号量?

时间:2020-03-05 18:45:01  来源:igfitidea点击:

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

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

解决方案

回答

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

回答

@克雷格:

A semaphore is a way to lock a
  resource so that it is guaranteed that
  while a piece of code is executed,
  only this piece of code has access to
  that resource. This keeps two threads
  from concurrently accesing a resource,
  which can cause problems.

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

回答

迈克尔·巴尔(Michael Barr)揭秘的互斥量和信号量文章是一个简短的简短介绍,介绍了互斥量和信号量与众不同之处以及何时以及不应该使用它们。我在这里摘录了几个关键段落。

关键是互斥锁应用于保护共享资源,而信号灯应用于信令。通常,我们不应使用信号量来保护共享资源,也不应使用互斥量来发信号。例如,在使用信号量来保护共享资源方面,使用保镖类比存在一些问题,我们可以通过这种方式使用它们,但是这可能会导致难以诊断错误。

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.

...

在这一点上,使用浴室钥匙作为保护浴室共享资源的想法进行了有趣的类比。如果商店只有一个浴室,那么一个钥匙就足以保护该资源并防止多个人同时使用它。

如果有多个浴室,则可能会想像一个浴室那样对其进行键控并进行多个键操作,这类似于信号灯被滥用。一旦有了钥匙,我们实际上就不知道哪个浴室可用,如果我们沿着这条路走,我们可能最终将使用互斥锁来提供该信息,并确保我们不上已被占用的浴室。

信号量是保护几种基本相同的资源的错误工具,但这是许多人想到并使用它的方式。保镖的类比明显不同,没有几种相同类型的资源,而是有一种资源可以接受多个同时用户。我想可以在这种情况下使用信号量,但是在现实世界中很少有这样的类比实际情况,即通常有几种同类型的信号,但是仍然有个别资源(例如浴室)无法使用道路。

...

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.

...

这里要指出的一点是,互斥锁会以一种不好的方式干扰实时操作系统,从而导致优先级倒置,由于资源共享,优先级较低的任务可能会在优先级较高的任务之前执行。简而言之,当优先级较低的任务使用互斥锁抢​​占资源A,然后尝试抢夺B,但由于B不可用而暂停时,就会发生这种情况。在等待期间,出现了更高优先级的任务,需要A,但是它已经被捆绑,并且由于等待B而被一个甚至没有运行的进程所束缚。有很多方法可以解决此问题,但是大多数情况下它是固定的通过更改互斥锁和任务管理器。在这种情况下,互斥锁比二进制信号量要复杂得多,并且在这种情况下使用信号量会导致优先级倒置,因为任务管理器没有意识到优先级倒置并且无法采取措施对其进行纠正。

...

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.

互斥体:资源共享

信号量:信号

在未仔细考虑副作用的情况下,请勿将另一种药物用于另一种药物。

回答

互斥体:对资源的独占成员访问

信号量:对资源的n成员访问

也就是说,互斥锁可用于同步访问计数器,文件,数据库等。

一个sempahore可以做同样的事情,但是支持固定数量的同时呼叫者。例如,我可以将数据库调用包装在semaphore(3)中,这样我的多线程应用程序最多可以同时连接3个数据库。所有尝试将阻塞,直到打开三个插槽之一。它们使像天真节流这样的事情变得非常,非常容易。

回答

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

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

如其他答案所述,信号量可用于将对特定资源的访问限制为最大(但可变)进程数。

回答

可以将信号量视为夜总会的蹦蹦跳跳。一次有大量的人员被允许进入俱乐部。如果俱乐部已满,则不允许任何人进入,但一旦一个人离开,另一个人可能会进入。

这只是限制特定资源的使用者数量的一种方法。例如,限制同时调用应用程序中的数据库的次数。

这是C语言中非常教学法的示例:-)

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TheNightclub
{
    public class Program
    {
        public static Semaphore Bouncer { get; set; }

        public static void Main(string[] args)
        {
            // Create the semaphore with 3 slots, where 3 are available.
            Bouncer = new Semaphore(3, 3);

            // Open the nightclub.
            OpenNightclub();
        }

        public static void OpenNightclub()
        {
            for (int i = 1; i <= 50; i++)
            {
                // Let each guest enter on an own thread.
                Thread thread = new Thread(new ParameterizedThreadStart(Guest));
                thread.Start(i);
            }
        }

        public static void Guest(object args)
        {
            // Wait to enter the nightclub (a semaphore to be released).
            Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
            Bouncer.WaitOne();          

            // Do some dancing.
            Console.WriteLine("Guest {0} is doing some dancing.", args);
            Thread.Sleep(500);

            // Let one guest out (release one semaphore).
            Console.WriteLine("Guest {0} is leaving the nightclub.", args);
            Bouncer.Release(1);
        }
    }
}

回答

信号量也可以用作...信号量。
例如,如果我们有多个进程将数据放入队列中,而只有一个任务在使用该队列中的数据。如果我们不希望耗时任务不断在队列中轮询可用数据,则可以使用信号灯。

在此,信号灯不用作排除机制,而是用作信号传递机制。
消耗任务正在等待信号量
生产任务正在信号量上发布。

这样,消费任务仅在有数据要出队时才运行