6

我已经编写了我希望是在 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

4 回答 4

4

这是假设 Win32 事件是昂贵的。他们不是,我能想到的没有什么比活动更便宜的了。.NET 设计人员决定使用 Win32 事件来实现 MRE 和 ARE 是个好主意,这就是一个重要的暗示。

更换的真正成本是当您遇到线程竞赛并且不知道是什么原因时您将体验到的主要 FUD。

于 2010-05-12T11:49:39.927 回答
2

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

于 2010-11-04T18:14:38.557 回答
1

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

于 2010-05-12T13:18:35.930 回答
0

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

但是,它们的速度有很大的不同:

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

查看此内容以获取有关 AutoResetEvent 和替代方案的完整代码示例和性能比较。

于 2013-04-07T22:51:10.370 回答