为啥 BCL 中没有 AutoResetEventSlim?
Posted
技术标签:
【中文标题】为啥 BCL 中没有 AutoResetEventSlim?【英文标题】:Why no AutoResetEventSlim in BCL?为什么 BCL 中没有 AutoResetEventSlim? 【发布时间】:2012-01-03 03:54:06 【问题描述】:为什么 BCL 中没有 AutoResetEventSlim
类?
可以用ManualResetEventSlim
模拟吗?
【问题讨论】:
AutoResetEventSlim
可以使用SemaphoreSlim
进行模拟。
【参考方案1】:
ManualResetEvent
和 ManualResetEventSlim
都被设计为在调用后保持信号状态。这通常适用于与AutoResetEvent
截然不同的场景。
AutoResetEvent
使用后立即返回无信号状态,这通常用于一组不同的场景。来自 AutoResetEvents 文档:
通常,当线程需要独占访问资源时,您会使用此类。
ManualResetEvent
(和Slim
)通常用于以下场景:
此通信涉及一个线程必须在其他线程继续之前完成的任务。
由于AutoResetEvent
最常用于有多个线程共享资源的场景,因此等待时间通常不会非常短。但是,ManualResetEventSlim
仅在您事先知道等待时间很短的情况下才真正打算使用。如果您的等待时间不会很短,那么您应该改用ManualResetEvent
。有关详细信息,请参阅difference between MRE and MRES 上的文档。
当您的等待时间较长时(这将是AutoResetEvent
的正常情况),“slim”版本实际上更糟,因为它恢复为使用等待句柄。
【讨论】:
我认为不同的典型用例根本没有说明预期的等待时间。事实上,我希望“多个线程共享同一资源”比“一个线程必须在其他线程可以继续之前完成”的等待更少。【参考方案2】:我也被这个事实困扰。
但是,您似乎可以使用带有特殊配置的简单SemaphoreSlim
模拟AutoResetEvent(Slim)
:
SemaphoreSlim Lock = new SemaphoreSlim( 1, 1 );
在the constructor中,第一个参数定义了信号量的初始状态:1
表示可以进入一个线程,0
表示必须先释放信号量。所以new AutoResetEvent( true )
转换为new SemaphoreSlim( 1, 1 )
和new AutoResetEvent( false )
分别转换为new SemaphoreSlim( 0, 1 )
。
第二个参数定义了可以同时进入信号量的最大线程数。将其设置为 1
使其行为类似于 AutoResetEvent
。
SemaphoreSlim
的另一个好处是,在 4.5 中使用新的async
/await
模式,该类收到了一个可以等待的.WaitAsync()
method。因此,在这种情况下,无需再手动创建可等待的等待原语。
希望这会有所帮助。
【讨论】:
使用SemaphoreSlim
作为AutoResetEvent
的替代品时的一个复杂情况:尝试在已达到最大计数时释放将抛出SemaphoreFullException
,这与在已设置事件时设置事件不同。
【参考方案3】:
引用微软的 Josh Phillips (original here):
至于 AutoResetEventSlim.. 是否有您需要它的场景? 说实话,创建一个 AutoResetEvent 非常困难,而且 用例非常有限,因此我们优先考虑其他方面的工作。 如果你真的需要一个,我很想听听,所以我们 可以考虑创建一个!
扩展评论:您可以只使用手动事件并确保在等待后始终将其重置。
如果等待和重置之间的微小延迟导致了问题,那么无论如何都可能存在根本问题。例如,如果有多个消费者并且您应该只让一个通过,那么可能某个事件不是适合该工作的工具,您应该考虑 SemaphoreSlim
甚至只是原始的 Monitor
。
【讨论】:
以上是关于为啥 BCL 中没有 AutoResetEventSlim?的主要内容,如果未能解决你的问题,请参考以下文章
AutoResetEvent和ManualResetEvent理解 z