我需要在ManualResetEvent上调用Close()吗?
我一直在阅读.NET Threading,并正在研究一些使用ManualResetEvent的代码。 我在互联网上找到了很多代码示例。 但是,在阅读WaitHandle的文档时,我看到以下内容:
WaitHandle实现了Dispose模式。 请参阅实现Finalize和Dispose以清理非托管资源。
没有任何样本似乎在他们创建的ManualResetEvent对象上调用.Close(), 甚至是来自pfxteam博客的好的Recursion and Concurrency文章 ( 编辑 – 这有一个我错过的使用块)。 这只是示例疏忽,还是不需要? 我很好奇,因为WaitHandle“封装了特定于操作系统的对象”,因此很容易出现资源泄漏。
通常,如果一个对象实现了IDisposable
那么它是出于某种原因这样做的,你应该调用Dispose
(或者Close
,视情况而定)。 在您的站点示例中,ManualResetEvent包含在using
语句中,该语句将“自动”处理调用Dispose
。 在这种情况下, Close
与Dispose
同义(在提供Close
方法的大多数IDisposable
实现中都是如此)。
示例中的代码:
using (var mre = new ManualResetEvent(false)) { ... }
扩展到
var mre = new ManualResetEvent(false); try { ... } finally { ((IDispoable)mre).Dispose(); }
我最近转发了一篇摘自C#4.0的Nutshell:The Definitive Reference作者:Joseph Albahari,Ben Albahari。 在页834,在第21章:线程中有一节讨论这个。
处理等待句柄
完成等待句柄后,可以调用其Close方法释放操作系统资源。 或者,您可以简单地删除对等待句柄的所有引用,并允许垃圾收集器稍后为您执行该作业(等待句柄实现处理模式,由此终结器调用Close )。 这是依赖此备份(可以说)可接受的少数场景之一,因为等待句柄具有轻微的操作系统负担(异步委托完全依赖于此机制来释放其IAsyncResult的等待句柄)。
应用程序域卸载时会自动释放等待句柄。
Close在ManualResetEvent的Dispose中处理,并由’using’语句调用。
http://msdn.microsoft.com/en-us/library/yh598w02%28VS.100%29.aspx
你会注意到代码
using (var mre = new ManualResetEvent(false)) { // Process the left child asynchronously ThreadPool.QueueUserWorkItem(delegate { Process(tree.Left, action); mre.Set(); }); // Process current node and right child synchronously action(tree.Data); Process(tree.Right, action); // Wait for the left child mre.WaitOne(); }
使用’using’关键字。 即使代码抛出exception,这也会在完成后自动调用dispose方法。
我经常使用ManualResetEvent
并且不认为我曾经在单个方法中使用过它 – 它总是一个类的实例字段。 因此, using()
通常不适用。
如果您有一个类实例字段是ManualResetEvent
的实例,请使您的类实现IDisposable
并在Dispose()
方法中调用ManualResetEvent.Close()
。 然后在你的类的所有用法中,你需要使用using()
或使包含类实现IDisposable
并重复,并重复…
如果您使用带有匿名方法的ManualResetEvent
,那么它显然很有用。 但正如萨姆所说,他们经常可以传递给工人,然后设置和关闭。
所以我会说这取决于你如何使用它的上下文 – MSDN WaitHandle.WaitAll()代码示例有一个很好的例子我的意思。
下面是一个基于MSDN示例的示例,该示例说明如何using
语句创建WaitHandles将是exception:
System.ObjectDisposedException
“安全手柄已关闭”
const int threads = 25; void ManualWaitHandle() { ManualResetEvent[] manualEvents = new ManualResetEvent[threads]; for (int i = 0; i < threads; i++) { using (ManualResetEvent manualResetEvent = new ManualResetEvent(false)) { ThreadPool.QueueUserWorkItem(new WaitCallback(ManualWaitHandleThread), new FileState("filename", manualResetEvent)); manualEvents[i] = manualResetEvent; } } WaitHandle.WaitAll(manualEvents); } void ManualWaitHandleThread(object state) { FileState filestate = (FileState) state; Thread.Sleep(100); filestate.ManualEvent.Set(); } class FileState { public string Filename { get;set; } public ManualResetEvent ManualEvent { get; set; } public FileState(string fileName, ManualResetEvent manualEvent) { Filename = fileName; ManualEvent = manualEvent; } }
- Paypal IPN模拟器始终返回INVALID,尽管回发正确
- 使用从外部解决方案托管在Windows服务中的WCF服务
- 如何在C#中使用Telegram API发送消息
- 如何从用户控件中引发自定义路由事件?
- 检查动画片段是否已完成
- 仅允许TextBox中的整数
- Azure WebSites或Azure云服务上的MVC4 API :’System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption’
- 如何检查C#中是否安装了特定版本的Flash播放器。?
- RuntimeType:http://schemas.datacontract.org/2004/07/System’不是预期的