C#中Manual / AutoResetEvent的轻量级替代品

时间:2010-05-12 07:57:26

标签: c# multithreading autoresetevent manualresetevent

我已经编写了我希望在C#/ .NET中使用ManualResetEvent和AutoResetEvent类的轻量级替代方法。这背后的原因是让事件像功能一样没有使用内核锁定对象的重量。

尽管代码似乎在测试和生产中都运行良好,但是对于所有可能性来说这种方法都是正确的,这可能是一件令人担忧的事情,我会谦虚地请求StackOverflow人群对此提出任何建设性意见和批评。希望(经过审核)这对其他人有用。

用法应与使用Set()的Notify()的Manual / AutoResetEvent类相似。

这里是:

using System;
using System.Threading;

public class Signal
{
  private readonly object _lock = new object();
  private readonly bool _autoResetSignal;
  private bool _notified;

  public Signal()
    : this(false, false)
  {
  }

  public Signal(bool initialState, bool autoReset)
  {
    _autoResetSignal = autoReset;
    _notified = initialState;
  }

  public virtual void Notify()
  {
    lock (_lock)
    {
      // first time?
      if (!_notified)
      {
        // set the flag
        _notified = true;

        // unblock a thread which is waiting on this signal 
        Monitor.Pulse(_lock);
      }
    }
  }

  public void Wait()
  {
    Wait(Timeout.Infinite);
  }

  public virtual bool Wait(int milliseconds)
  {
    lock (_lock)
    {
      bool ret = true;
      // this check needs to be inside the lock otherwise you can get nailed
      // with a race condition where the notify thread sets the flag AFTER 
      // the waiting thread has checked it and acquires the lock and does the 
      // pulse before the Monitor.Wait below - when this happens the caller
      // will wait forever as he "just missed" the only pulse which is ever 
      // going to happen 
      if (!_notified)
      {
        ret = Monitor.Wait(_lock, milliseconds);
      }

      if (_autoResetSignal)
      {
        _notified = false;
      }
      return (ret);
    }
  }
}

4 个答案:

答案 0 :(得分:4)

这可以假设Win32事件很昂贵。他们不是,我认为这比事件便宜。一个主要暗示是.NET设计者决定使用Win32事件来实现MRE和ARE是个好主意。

您更换的真正成本是您在进行穿线比赛时遇到的主要FUD,并且不知道是什么原因造成的。

答案 1 :(得分:1)

不幸的是,鉴于Win32同步原语,正确的Monitor实现是相当重要的。我最初的怀疑是,“锁定”在资源使用方面比事件更重(并且可能建立在事件之上)。

答案 2 :(得分:1)

优化AutoResetEvent性能的一种方法是将其状态(发信号/非信号)保存在您自己的变量中,因此在进入内核并实际使用事件对象之前,您可以只检查应用变量的状态并始终保持用户模式 几个月前我发布了demonstration这个概念。

答案 3 :(得分:0)

通常,任何同步都很慢,因此最好避免它们。

然而,他们的速度之间存在很大差异:

支持的CPU Interlocked Exchange是最快的,而简单的布尔标志仍然胜过AutoresetEvent。

查看完整代码示例和performance comparisons on AutoResetEvent and alternatives.