我需要对 ManualResetEvent 调用 Close() 吗?

发布于 2024-08-21 17:09:54 字数 703 浏览 8 评论 0原文

我一直在阅读 .NET Threading 并正在研究一些使用 手动重置事件。我在互联网上找到了很多代码示例。但是,在阅读 WaitHandle 的文档时,我看到下列:

WaitHandle 实现 Dispose 图案。请参阅实施 Finalize 和 处置清理非托管 资源。

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

I've been reading up on .NET Threading and was working on some code that uses a ManualResetEvent. I have found lots of code samples on the internet. However, when reading the documentation for WaitHandle, I saw the following:

WaitHandle implements the Dispose
pattern. See Implementing Finalize and
Dispose to Clean Up Unmanaged
Resources.

None of the samples seem to call .Close() on the ManualResetEvent objects they create, even the nice Recursion and Concurrency article from the pfxteam blog (Edit - this has a using block I has missed). Is this just example oversight, or not needed? I am curious because a WaitHandle "encapsulates operating system–specific objects," so there could easily be a resource leak.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

眼泪也成诗 2024-08-28 17:09:54

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

处置等待句柄

等待结束后
句柄,你可以调用它的Close方法
释放操作系统
资源。或者,您可以
只需删除所有对等待的引用
处理并允许垃圾收集器
稍后为你做这项工作
(等待句柄实施处置
终结器调用的模式
关闭)。这是为数不多的之一
依赖此备份的场景
(可以说)可以接受,因为等等
句柄的操作系统负担较轻
(异步委托依赖于
正是这个机制来释放
他们的IAsyncResult的等待句柄)。

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

I was recently forwarded an excerpt from C# 4.0 in a Nutshell: The Definitive Reference By Joseph Albahari, Ben Albahari. On page 834, in Chapter 21: Threading there is a section talking about this.

Disposing Wait Handles

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.

拧巴小姐 2024-08-28 17:09:54

一般来说,如果一个对象实现了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();
}

In general, if an object implements IDisposable it is doing so for a reason and you should call Dispose (or Close, as the case may be). In the example you site, the ManualResetEvent is wrapped inside a using statement, which will "automatically" handle calling Dispose. In this case, Close is synonymous with Dispose (which is true in most IDisposable implementations that provide a Close method).

The code from the example:

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

expands to

var mre = new ManualResetEvent(false);
try
{
   ...
}
finally
{
   ((IDispoable)mre).Dispose();
}
诗笺 2024-08-28 17:09:54

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

http://msdn.microsoft.com/en-我们/库/yh598w02%28VS.100%29.aspx

The Close is handled inside ManualResetEvent's Dispose, and that's called by the 'using' statement.

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

眼泪也成诗 2024-08-28 17:09:54

您会注意到代码

 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 方法。

You'll notice the code

 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();
}

uses the 'using' keyword. This automatically calls the dispose method when finished even if the code throws an exception.

旧情别恋 2024-08-28 17:09:54

我经常使用 ManualResetEvent 并且认为我从未在单个方法中使用过它 - 它始终是类的实例字段。因此 using() 通常不适用。

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

I've used ManualResetEvent a lot and don't think I've ever used it inside a single method--it's always an instance field of a class. Therefore using() often does not apply.

If you have a class instance field that is an instance of ManualResetEvent, make your class implement IDisposable and in your Dispose() method call ManualResetEvent.Close(). Then in all usages of your class, you need to use using() or make the containing class implement IDisposable and repeat, and repeat...

错々过的事 2024-08-28 17:09:54

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

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

下面是一个基于 MSDN 示例的示例,说明如何使用 using 语句创建 WaitHandles 会出现异常:

System.ObjectDisposeException
“安全手柄已关闭”

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

If you're using a ManualResetEvent with anonymous methods then it's obviously useful. But as Sam mentioned they can often be passed around into workers, and then set and closed.

So I would say it depends on the context of how you are using it - the MSDN WaitHandle.WaitAll() code sample has a good example of what I mean.

Here's an example based on the MSDN sample of how creating the WaitHandles with a using statement would exception:

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文