似乎没有任何示例调用它们创建的ManualResetEvent对象的.Close()方法,即使是来自pfxteam博客的漂亮的Recursion and Concurrency文章(编辑 - 我错过了一个using块)。这只是示例的疏忽,还是不需要?我很好奇,因为WaitHandle“封装操作系统特定的对象”,所以可能会出现资源泄漏。WaitHandle实现了Dispose模式。参见实现Finalize和Dispose以清理非托管资源。
似乎没有任何示例调用它们创建的ManualResetEvent对象的.Close()方法,即使是来自pfxteam博客的漂亮的Recursion and Concurrency文章(编辑 - 我错过了一个using块)。这只是示例的疏忽,还是不需要?我很好奇,因为WaitHandle“封装操作系统特定的对象”,所以可能会出现资源泄漏。WaitHandle实现了Dispose模式。参见实现Finalize和Dispose以清理非托管资源。
最近我收到了一段来自《C# 4.0权威指南》(作者:Joseph Albahari, Ben Albahari)的摘录。在第21章:多线程的第834页中,有一个关于如下内容的小节。
释放等待句柄资源
当您使用完一个等待句柄后,可以调用其Close方法以释放操作系统资源。或者,您可以简单地删除所有对等待句柄的引用,并允许垃圾回收器稍后为您完成此任务(等待句柄实现了可处理方式,其中终结器调用Close)。这是仅有几种情况之一,其中依赖于这种备份(可能)是可以接受的,因为等待句柄具有轻量级的操作系统负担(异步委托依赖于正是这种机制来释放它们的IAsyncResult等待句柄)。
应用程序域卸载时,等待句柄会被自动释放。
通常,如果一个对象实现了 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();
}
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' 关键字。即使代码抛出异常,它也会在完成时自动调用 dispose 方法。
ManualResetEvent
,那么它显然是有用的。但正如Sam所提到的,它们经常被传递到工作线程中,然后被设置和关闭。using
语句创建WaitHandles会出现异常:
System.ObjectDisposedException
"Safe handle has been closed"
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;
}
}
Close方法在ManualResetEvent的Dispose方法中处理,并且由'using'语句调用。
http://msdn.microsoft.com/en-us/library/yh598w02%28VS.100%29.aspx
我经常使用ManualResetEvent
,但我从来没有在单个方法中使用过它——它总是作为类的实例字段存在。因此,using()
通常不适用。
如果你有一个类实例字段是ManualResetEvent
的实例,请让你的类实现IDisposable
接口,并在Dispose()
方法中调用ManualResetEvent.Close()
。然后在所有使用该类的地方,你需要使用using()
或让包含该类的类实现IDisposable
并重复这个步骤,再重复......
WaitHandle
类不再拥有Finalize
方法,但我认为这并不意味着它们会泄漏。相反,清理工作在SafeHandle
类中处理,而WaitHandle
持有对其的引用。 - supercat