2010-02-10 25 views
14

我一直在阅读.NET线程,并且正在研究一些使用ManualResetEvent的代码。我在互联网上找到了很多代码示例。然而,阅读文档WaitHandle的时候,我看到以下内容:我是否需要在ManualResetEvent上调用Close()?

的WaitHandle实现的Dispose 模式。请参阅实施完成和 处置以清理非托管 资源。

无样品似乎对他们所创造的ManualResetEvent的对象调用.Close(),即使是好的Recursion and Concurrency从pfxteam博客编辑文章 - 这有使用块我已经错过一)。这仅仅是例子的监督,还是不需要?我很好奇,因为WaitHandle“封装了特定于操作系统的对象”,所以很容易出现资源泄漏。

回答

11

一般来说,如果一个对象实现了IDisposable它是这样做的原因,你应该叫Dispose(或Close,视情况而定)。在您的网站示例中,ManualResetEvent包装在using语句中,该语句将“自动”处理呼叫Dispose。在这种情况下,CloseDispose同义(在提供Close方法的大多数IDisposable实现中都是如此)。

从示例代码:

using (var mre = new ManualResetEvent(false)) 
{ 
    ... 
} 

扩展到

var mre = new ManualResetEvent(false); 
try 
{ 
    ... 
} 
finally 
{ 
    ((IDispoable)mre).Dispose(); 
} 
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(); 
} 

使用 '使用' 关键字。这会在完成时自动调用dispose方法,即使代码抛出异常。

+0

查看该代码时,我完全错过了使用块。感谢您指出。 – 2010-02-10 03:54:55

2

我用ManualResetEvent了很多,不认为我曾经用一个单一method--内它总是一个类的实例字段。因此using()通常不适用。

如果你有一个类的实例字段是ManualResetEvent一个实例,让你的类实现IDisposable并在Dispose()方法调用ManualResetEvent.Close()。然后在你的课程的所有用法中,你需要使用using()或使包含类实现IDisposable并重复,并重复...

2

如果你使用的是带匿名方法的ManualResetEvent,那么它显然是有用的。但是,正如山姆所说,他们经常可以被传播到工人身边,然后安置并关闭。

所以我会说这取决于你如何使用它的上下文 - the MSDN WaitHandle.WaitAll()代码示例有一个很好的例子,我的意思是。

这里的基础上如何与using语句创建WaitHandles会异常的MSDN样本的例子:

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; 
    } 
} 
+0

这似乎是一个示例,其中.Close()未在ManualResetEvent上调用,并且没有使用块。我不认为工作人员可以关闭它,因为主线程正在WaitHandle.WaitAll(manualEvents)调用中使用它。 – 2010-02-10 13:20:01

+0

@Kevin我的观点是WaitHandles数组无法包含在使用子句中时创建为*我认为*他们会在他们到达时关闭,但我需要检查。 – 2010-02-10 14:10:27

17

我最近被转发摘录自C# 4.0 in a Nutshell: The Definitive Reference By Joseph Albahari,Ben Albahar一世。在页834,在第21章:线程有一节讨论这一点。

处置等待句柄

一旦你有一个等待 句柄后,就可以调用它关闭方法 释放操作系统 资源。或者,你可以简单地 删除所有引用到等待 手柄,让垃圾回收 到以后的某个时候为你做的工作 (等待句柄落实处置 模式,即终结呼吁 关闭)。这是为数不多的 场景中对这个备份 依托是一个(可以说)可以接受的,因为等待 手柄有一个光OS负担 (异步委托依靠 正是这种机制来释放 他们的IAsyncResult的等待句柄)。

当应用程序 域卸载时会自动释放等待句柄 。

+0

WaitHandle.Finalize的文档说,不再有.NET 2.0的实现。您也可以使用反编译器来查看。 WaitHandle不再有终结器。我不知道为什么,但任何被抛弃的WaitHandle似乎都会泄漏它。请参阅http://msdn.microsoft.com/en-us/library/vstudio/bb291974(v=vs.90).aspx – Djof 2013-06-14 19:39:08

+4

@Djof:尽管'WaitHandle'不再有'Finalize'方法,我不'我认为这意味着他们会泄漏。相反,清理是在'WaitHandle'持有引用的'SafeHandle'中处理的。 – supercat 2013-09-13 21:33:24

相关问题