我一直在阅读.NET Threading,并正在研究一些使用ManualResetEvent的代码。我在互联网上找到了很多代码示例。但是,在阅读WaitHandle的文档时,我看到了以下内容:
WaitHandle实现了Dispose 图案。请参阅实现Finalize和 处理清理不受管理 资源。
没有一个样本似乎在他们创建的ManualResetEvent对象上调用.Close(),甚至是来自pfxteam博客的好Recursion and Concurrency文章( 编辑< / em> - 这有一个我错过的使用块)。这只是示例疏忽,还是不需要?我很好奇,因为WaitHandle“封装了特定于操作系统的对象”,因此很容易出现资源泄漏。
答案 0 :(得分:21)
我最近转发了C# 4.0 in a Nutshell: The Definitive Reference的摘录作者:Joseph Albahari,Ben Albahari。在页834,在第21章:线程中有一节讨论这个。
处置等待句柄
等待完成后 handle,您可以调用其关闭方法 发布操作系统 资源。或者,你可以 只需删除对等待的所有引用 处理并允许垃圾收集器 以后再为你做这份工作 (等待句柄实施处置 终结者调用的模式 关闭强>)。这是少数几个 依赖此备份的方案 是(可以说)是可以接受的,因为等待 句柄有轻微的操作系统负担 (异步代理依赖 正是这种机制才能释放 他们的 IAsyncResult的等待句柄。)
释放等待句柄 应用程序时自动执行 域名卸载。
答案 1 :(得分:11)
一般情况下,如果一个对象实现了IDisposable
,那么出于某种原因这样做了,你应该调用Dispose
(或Close
,视情况而定)。在您的站点示例中,ManualResetEvent包含在using
语句中,该语句将“自动”处理调用Dispose
。在这种情况下,Close
与Dispose
同义(在提供IDisposable
方法的大多数Close
实现中都是如此。
示例中的代码:
using (var mre = new ManualResetEvent(false))
{
...
}
扩展为
var mre = new ManualResetEvent(false);
try
{
...
}
finally
{
((IDispoable)mre).Dispose();
}
答案 2 :(得分:2)
Close在ManualResetEvent的Dispose中处理,并由'using'语句调用。
http://msdn.microsoft.com/en-us/library/yh598w02%28VS.100%29.aspx
答案 3 :(得分:2)
您会注意到代码
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方法。
答案 4 :(得分:2)
我经常使用ManualResetEvent
并且不认为我曾经在单个方法中使用它 - 它始终是类的实例字段。因此using()
通常不适用。
如果您的类实例字段是ManualResetEvent
的实例,请在您的IDisposable
方法调用Dispose()
中创建类实现ManualResetEvent.Close()
。然后在您班级的所有用法中,您需要使用using()
或使包含类实现IDisposable
并重复,然后重复...
答案 5 :(得分:2)
如果您使用匿名方法ManualResetEvent
,那么它显然很有用。但是,正如萨姆提到的那样,他们经常可以传递给工人,然后设置和关闭。
所以我会说这取决于你如何使用它的上下文 - the MSDN WaitHandle.WaitAll()代码示例有一个很好的例子我的意思。
以下是一个基于MSDN示例的示例,该示例说明使用using
语句创建WaitHandles将如何例外:
<强> 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;
}
}