急切地处理ManualResetEvent

我有一个类允许其他线程等到它使用ManualResetEventSlim完成一个操作。 (操作通常很简短)

这个类没有明确的生命周期,因此没有一个地方可以轻松关闭事件。
相反,我希望在事件结束后立即关闭事件 – 一旦发出信号,并且在任何等待的线程唤醒之后。

出于性能原因,我宁愿不使用锁。

这段代码是否是线程安全的,可以更快吗?

 volatile bool isCompleted; volatile int waitingCount; ManualResetEventSlim waiter = new ManualResetEventSlim(); //This method is called on any thread other than the one that calls OnCompleted public void WaitForCompletion() { if (isCompleted) return; Interlocked.Increment(ref waitingCount); Thread.MemoryBarrier(); if (!isCompleted) waiter.Wait(); if (0 == Interlocked.Decrement(ref waitingCount)) { waiter.Dispose(); waiter = null; } return; } //This method is called exactly once. protected internal virtual void OnCompleted(string result) { Result = result; isCompleted = true; Thread.MemoryBarrier(); if (waitingCount == 0) { waiter.Dispose(); waiter = null; } else waiter.Set(); } 

我在代码中看到的最重要的事情是在调用Dispose后将服务器设置为null 。 我负责管理非托管接口上的大量托管包装,当我转移到.Net 4.0时,这种做法在某些线程场景中回过头来咬我。

ManualResetEventSlim.Dispose上的MSDN信息表明它不是线程安全的,但是,查看其实际实现,从多个线程多次调用Dispose没有任何危险。 此外, IDisposable实现应该非常容忍多个调用(如其设计指南中所指定的)。

我玩过的一个想法会稍微重新排序OnCompleted以允许读者在完成后不久订阅它:

 //This method is called exactly once. protected internal virtual void OnCompleted(string result) { Result = result; isCompleted = true; waiter.Set(); Thread.MemoryBarrier(); if (waitingCount == 0) { waiter.Dispose(); } } 

更糟糕的是,有些条件下根本不会处理服务员。 如果在waitingCount > 0时调用OnCompleted ,则isCompleted标志将设置为true ,但服务器将不会被waitingCount > 0 当某些东西调用WaitForCompletion ,它会看到isCompletedtrue ,并立即退出。 waiter.Dispose永远不会被调用。

为什么不使用像SpinLock这样的东西 ,它使用与ManualResetEventSlim相同的逻辑? 如果您的等待通常非常短,那么锁可能不会争用,这是一个巨大的胜利。 如果等待很长,那么ManualResetEventSlim无论如何都要付出内核转换的代价。

您是否确定使用锁定会非常昂贵? 有“知道”,然后有测量。 。 。