我需要在ManualResetEvent上调用Close()吗?

时间:2010-02-10 02:58:55

标签: c# multithreading dispose waithandle resource-leak

我一直在阅读.NET Threading,并正在研究一些使用ManualResetEvent的代码。我在互联网上找到了很多代码示例。但是,在阅读WaitHandle的文档时,我看到了以下内容:

  

WaitHandle实现了Dispose   图案。请参阅实现Finalize和   处理清理不受管理   资源。

没有一个样本似乎在他们创建的ManualResetEvent对象上调用.Close(),甚至是来自pfxteam博客的好Recursion and Concurrency文章 编辑< / em> - 这有一个我错过的使用块)。这只是示例疏忽,还是不需要?我很好奇,因为WaitHandle“封装了特定于操作系统的对象”,因此很容易出现资源泄漏。

6 个答案:

答案 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。在这种情况下,CloseDispose同义(在提供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;
    }
}