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

swe*_*mre 5 c# multithreading manualresetevent autoresetevent

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

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

用法应类似于Manual/AutoResetEvent类,其中Notify()用于Set().

开始:

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 4

这是基于 Win32 事件代价昂贵的假设。事实并非如此,我认为没有什么比举办活动更便宜的了。这方面的一个主要暗示是 .NET 设计者认为使用 Win32 事件来实现 MRE 和 ARE 是一个好主意。

更换的真正成本是当您遇到线程争用且不知道原因时您会遇到的主要 FUD。

  • 假设 ARE 和 MRE 在幕后使用内核事件,这比监视器更昂贵。我很乐意被证明是错的:) (2认同)