16

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

WaitHandle 实现了 Dispose 模式。请参阅实施 Finalize 和 Dispose 以清理非托管资源。

没有一个样本似乎在他们创建的 ManualResetEvent 对象上调用 .Close(),即使是pfxteam 博客中不错的递归和并发文章(编辑- 这有一个我错过的 using 块)。这只是示例监督,还是不需要?我很好奇,因为 WaitHandle “封装了操作系统特定的对象”,因此很容易发生资源泄漏。

4

6 回答 6

22

我最近收到了一份来自C# 4.0 的摘要: Joseph Albahari、Ben Albahari 的权威参考。在第 834 页的第 21 章:线程中,有一节讨论了这一点。

处理等待句柄

Once you’ve finished with a wait handle, you can call its Close method to release the operating system resource. Alternatively, you can simply drop all references to the wait handle and allow the garbage collector to do the job for you sometime later (wait handles implement the disposal pattern whereby the finalizer calls Close). This is one of the few scenarios where relying on this backup is (arguably) acceptable, because wait handles have a light OS burden (asynchronous delegates rely on exactly this mechanism to release their IAsyncResult’s wait handle).

Wait handles are released automatically when an application domain unloads.

于 2010-03-01T18:44:20.257 回答
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();
}
于 2010-02-10T03:04:25.620 回答
2

Close 在 ManualResetEvent 的 Dispose 内处理,由“using”语句调用。

http://msdn.microsoft.com/en-us/library/yh598w02%28VS.100%29.aspx

于 2010-02-10T03:01:25.840 回答
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 方法。

于 2010-02-10T03:03:10.390 回答
2

我用过ManualResetEvent很多,但我认为我从来没有在单个方法中使用过它——它总是一个类的实例字段。因此using()往往不适用。

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

于 2010-02-10T03:44:12.580 回答
2

如果您使用的是ManualResetEvent匿名方法,那么它显然很有用。但正如 Sam 提到的,它们通常可以传递给工人,然后设置和关闭。

所以我想说这取决于你如何使用它的上下文 - 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;
    }
}
于 2010-02-10T11:01:37.413 回答