简体   繁体   English

AutoResetEvent和信号量与maximumCount = 1之间有什么区别吗?

[英]Is there any difference between an AutoResetEvent and a Semaphore with maximumCount = 1?

I'm going through the following article: 我正在阅读以下文章:

http://www.albahari.com/threading http://www.albahari.com/threading

and I cannot get to realize the difference between an AutoResetEvent and a Semaphore initialized with maximumCount = 1. Just to see if I'm getting things right... is there any difference in these two constructs, given that usage? 我无法理解AutoResetEvent和用maximumCount = 1初始化的信号量之间的区别。只是为了看看我是否正确...这两种结构有什么不同,给定使用?

Thanks! 谢谢!

Yes, there certainly is a difference. 是的,确实存在差异。 A Semaphore is used to throttle access to a resource or block of code. Semaphore用于限制对资源或代码块的访问。 When WaitOne is called a thread will block until a count from the semaphore becomes available. WaitOne线程将阻塞,直到信号量的计数变为可用。 To make a count availabe you would call Release . 要使计数可用,您可以调用Release A semaphore with a maximum count of 1 is often called a binary semaphore. 最大计数为1的信号量通常称为二进制信号量。 A semaphore of this nature only allows access to a resource or block code from a single thread. 这种性质的信号量只允许从单个线程访问资源或块代码。 You could use a binary semaphore in place of a mutex or monitor. 您可以使用二进制信号量代替互斥锁或监视器。 The important thing to remember about the Semaphore is that its state is manually controlled via calls to WaitOne and Release . 关于Semaphore的重要一点是它的状态是通过调用WaitOneRelease手动控制的。

An AutoResetEvent on the other hand is primarily used as a signaling mechanism. 另一方面, AutoResetEvent主要用作信令机制。 One thread will block via a call to WaitOne waiting for a signal. 一个线程将通过调用WaitOne等待信号来阻塞。 Another thread will call Set to initiate that signal. 另一个线程将调用Set来启动该信号。 An ARE publishes this signal to one and only one thread and then immediately resets the ARE to an unsignaled state. ARE将此信号发布到一个且仅一个线程,然后立即将ARE重置为未信号状态。 The important thing to remember about the AutoResetEvent is that it is manually signaled via a call to Set and automatically reset after when a single call to WaitOne returns. 关于AutoResetEvent的重要一点是,它通过调用Set 手动发出信号,并在单次调用WaitOne返回后自动重置。

So here is a summary of differences: 所以这里是差异的总结:

  • A Semaphore 's state is manually controlled. Semaphore的状态是手动控制的。
  • A AutoResetEvent 's state is manually set, but automatically reset. 手动设置AutoResetEvent的状态,但会自动重置。
  • With a Semaphore threads typically balance the Release and WaitOne calls. 使用Semaphore线程通常可以平衡ReleaseWaitOne调用。
  • With a AutoResetEvent one thread is typically designated as the signaler and another is the waiter. 使用AutoResetEvent一个线程通常被指定为信号器,另一个是服务员。
  • A Semaphore throttles access to a resource or block of code. Semaphore限制访问资源或代码块。
  • A AutoResetEvent signals a thread to take some action. AutoResetEvent通知线程采取某些操作。

Think of a AutoResetEvent as a door to a hallway. AutoResetEvent视为走廊的大门。 The door will allow one and only one person through the door after receiving a command to do so. 在收到命令后,门将允许一个人和一个人通过门。 Once a person goes through the door it immediately closes and waits for another command. 一旦一个人进门,它立即关闭并等待另一个命令。 As long as the door keeps receiving new commands the hallway is free to fill with as many people as the number of commands given. 只要门继续接收新命令,走廊就可以自由地填充与给定命令数量一样多的人。

Think of a Semaphore as a door to the same hallway. Semaphore想象成同一个走廊的门。 The door will allow a certain number of people in the hallway. 门将允许走廊里的一定数量的人。 The door remains open until the hallway reaches its occupancy limit at which time the door closes. 门保持打开,直到走廊达到占用限制,此时门关闭。 After someone leaves the hallway through the other side then this door opens again. 当有人离开走廊通过另一侧后,这扇门再次打开。

Update: 更新:

Here is the simplest possible example that demonstrates that something is clearly different. 这是最简单的可能示例,表明某些事情明显不同。

static void Main()
{
    var are = new AutoResetEvent(false);
    are.Set();
    are.Set();

    var semaphore = new Semaphore(0, 1);
    semaphore.Release();
    semaphore.Release();
}

It comes as no surprise that you will get an exception on the second semaphore.Release call whereas the second call to Set passes through just fine. 毫无疑问,你会在第二个semaphore.Release上得到一个异常。 semaphore.Release呼叫,而第二次调用Set通过就好了。 The reason is because an ARE is setting a boolean flag whereas the semaphore is attempting to increase the count. 原因是因为ARE正在设置布尔标志,而信号量正在尝试增加计数。

The WaitOne methods will work the same way, but the Release and Set methods will not. WaitOne方法将以相同的方式工作,但ReleaseSet方法不会。 It is for this reason that a binary semaphore is not interchangable with an ARE. 正是由于这个原因,二进制信号量不能与ARE互换。 However, an ARE could be interchangable with a binary semaphore in some cases. 但是,在某些情况下,ARE可以与二进制信号量互换。

One scenario where there is overlap is in the case of a latch for a single thread. 存在重叠的一种情况是针对单个线程的锁存器的情况。

public static void Main()
{
  var latch = new AutoResetEvent(false);

  new Thread(
    () =>
    {
      latch.WaitOne(); // Wait for the latch.
    }).Start();

  latch.Set(); // Release the latch.
}

Here is a scenario that can only be satisfied by a AutoResetEvent . 这是一个只能由AutoResetEvent满足的场景。

static void Main()
{
    var are = new AutoResetEvent(false);

    new Thread(
        () =>
        {
            while (true)
            {
                are.WaitOne();
                Console.WriteLine("go");
                Thread.Sleep(2000);
            }
        }).Start();

    while (true)
    {
        are.Set();
        Console.WriteLine("pulse");
        Thread.Sleep(1000);
    }

}

An AutoResetEvent , to use Joe Albahari's metaphor : 一个AutoResetEvent ,使用Joe Albahari的比喻

is like a ticket turnstile: inserting a ticket lets exactly one person through 就像一个十字转门票:插入一张票只允许一个人穿过

so it's like a one-way door. 所以它就像一扇单门。

By contrast, a Semaphore with a count of one is like a room that can only hold one person and it has an "Occupied" sign. 相比之下,计数为1的Semaphore就像一个只能容纳一个人的房间,它有一个“被占用”的标志。 Semaphores are for controlling access to resources (the room) and the count specifies how many of the resources there are (how many people can fit in the room). 信号量用于控制对资源(房间)的访问,并且计数指定有多少资源(可以容纳多少人在房间中)。

Mostly the same from the perspective of user, one minor difference is multiple consecutive signals on AutoResetEvent will succeed which makes it inappropriate to model the resource produce consumption problem. 从用户的角度来看大致相同,一个小的区别是AutoResetEvent上的多个连续信号将成功,这使得模拟资源产生消费问题变得不合适。 Check out below article - "An auto-reset event is just a stupid semaphore". 查看下面的文章 - “自动重置事件只是一个愚蠢的信号量”。

http://blogs.msdn.com/b/oldnewthing/archive/2006/06/22/642849.aspx http://blogs.msdn.com/b/oldnewthing/archive/2006/06/22/642849.aspx

A semaphore with max 1 is just like a normal System.Threading.Monitor or a lock "if we ignore the fact that named system semaphores are visible throughout the operating system.." which provide a critical section "Only one thread is allow to access to this method or recourse and when finish using allow other thread to use it "if there is a waiting thread that is blocked until the current thread finish the using of the resource"." 最大1的信号量就像一个普通的System.Threading.Monitor或一个锁 “如果我们忽略命名系统信号量在整个操作系统中可见的事实......”它提供了一个关键部分 “只允许一个线程访问对于这种方法或求助,当完成使用时允许其他线程使用它“如果有一个等待的线程被阻塞,直到当前线程完成资源的使用”。 so only one thread can access a resource. 所以只有一个线程可以访问资源。

You can think of AutoResetEvent as a notifier , a thread will be wait until have notification from another thread to proceed and the other thread later will set to make another thread to wait for notification again "note that AutoResetEvent will automatically set the waiting thread again"... 您可以将AutoResetEvent视为通知程序 ,线程将等待直到另一个线程的通知继续进行,而另一个线程稍后将设置为使另一个线程再次等待通知“请注意,AutoResetEvent将自动再次设置等待线程” ...

An example to AutoRestEvent is producer/consumer using a collection, first thread will be waiting and element to be added to consume it, another thread "producer" whenever an element is added it signals "notify" a waiting thread "that were blocked waiting the notification", the first thread then will handle "consume" that new added element and then wait again until another element is added.. AutoRestEvent的一个例子是生产者/消费者使用集合,第一个线程将等待并且元素被添加以消耗它,另一个线程“生产者”每当添加一个元素时它发出信号“通知”等待线程“被阻止等待通知“,然后第一个线程将处理”消耗“新添加的元素,然后再次等待,直到添加另一个元素为止。

//Edit: If you already know the different between AutoResetEvent and the Semaphore and asking "as your comment" //编辑:如果您已经知道AutoResetEventSemaphore之间的不同并询问“作为您的评论”

If we restricted ourselves to using only WaitOne and Set for an ARE 如果我们仅限于使用WaitOne和Set for ARE

If you just using _autoResetEvent.WaitOne() and _autoResetEvent.Set() then you can achieve the same result -but you should use it carefully- by using _semaphore.WaitOne() and _semaphore.Release() : 如果您只使用_autoResetEvent.WaitOne()_autoResetEvent.Set() 那么您可以获得相同的结果 - 但是您应该小心使用它 -使用_semaphore.WaitOne()_semaphore.Release()

AutoResetEVent _autoResetEvent = new AutoResetEvent(true);
Semaphore _semaphore = new Semaphore(1, 1);

private void Foo()
{
    _autoResetEvent.WaitOne();
    try
    {
        //some code
        Console.WriteLine("Thread At Foo Entered {0}", Thread.CurrentThread.ManagedThreadId);
    }
    finaly
    {
        _autoResetEvent.Set();
    }
}

private void Bar()
{
    _semaphore.WaitOne();
    try
    {
        //some code
        Console.WriteLine("Thread At Bar Entered {0}", Thread.CurrentThread.ManagedThreadId);
    }
    finaly
    {
        _semaphore.Release();
    }
}

void Main()
{
    new Thread(Foo) { IsBackground = true }.Start();
    new Thread(Foo) { IsBackground = true }.Start();
    new Thread(Bar) { IsBackground = true }.Start();
    new Thread(Bar) { IsBackground = true }.Start();

    Thread.Sleep(2000);//give it some time to execute.
    Console.ReadLine();
}

//output is something like this:
Thread At Foo Entered 11
Thread At Foo Entered 12
Thread At Far Entered 13
Thread At Far Entered 14

A Semaphore is used to control the access to a critical section. 信号量用于控制对关键部分的访问。 Auto/ManualResetEvent is used when you want to signal other threads that a certain event has occurred so they can react on it - they have not really something to do with guarding the entry into a critical section. 当你想要向其他线程发出某个特定事件发生的信号时,会使用Auto / ManualResetEvent,这样它们就可以对它做出反应 - 它们与保护关键部分的条目无关。

I'm not sure which particular usage you refer to but I guess you could use locks and events to implement a semaphore so the answer to your question probably is no and yes depending on what you are after. 我不确定你提到的具体用法,但我想你可以使用锁和事件来实现一个信号量,所以你的问题的答案可能是肯定的,是的,取决于你所追求的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM