16

私は.NETThreadingを読んでいて、 ManualResetEventを使用するいくつかのコードに取り組んでいました。私はインターネット上でたくさんのコードサンプルを見つけました。ただし、WaitHandleのドキュメントを読んだときに、次のことがわかりました。

WaitHandleはDisposeパターンを実装します。管理されていないリソースをクリーンアップするためのファイナライズと破棄の実装を参照してください。

作成したManualResetEventオブジェクトで.Close()を呼び出すサンプルはなく、pfxteamブログのRecursion and Concurrencyの記事もあります(編集-これには、私が見逃したusingブロックがあります)。これは単なる見落としの例ですか、それとも必要ありませんか?WaitHandleは「オペレーティングシステム固有のオブジェクトをカプセル化する」ため、リソースリークが発生しやすいので不思議です。

4

6 に答える 6

22

私は最近、 C# 4.0からの抜粋を転送されました: The Definitive Reference By Joseph Albahari, Ben Albahari. 834 ページの第 21 章: スレッドには、これについて話しているセクションがあります。

待機ハンドルの破棄

待機ハンドルの処理が完了したら、そのCloseメソッドを呼び出して、オペレーティング システムのリソースを解放できます。または、単純に待機ハンドルへのすべての参照を削除し、後でガベージ コレクターがジョブを実行できるようにすることもできます (待機ハンドルは、ファイナライザーがCloseを呼び出す破棄パターンを実装し ます)。これは、このバックアップに依存することが (ほぼ間違いなく) 許容される数少ないシナリオの 1 つです。これは、待機ハンドルは OS の負担が軽いためです (非同期デリゲートは、まさにこのメカニズムに依存してIAsyncResult の待機ハンドルを解放します)。

アプリケーション ドメインがアンロードされると、待機ハンドルが自動的に解放されます。

于 2010-03-01T18:44:20.257 に答える
11

一般に、オブジェクトが実装IDisposableしている場合、それは何らかの理由で実装されており、 Dispose(またはClose、場合によっては) を呼び出す必要があります。サイトの例では、 ManualResetEvent はusingステートメント内にラップされており、呼び出しを「自動的に」処理しDisposeます。この場合、は (メソッドを提供するほとんどの実装に当てはまります)Closeと同義です。DisposeIDisposableClose

例のコード:

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

'using'キーワードを使用します。これにより、コードが例外をスローした場合でも、終了時にdisposeメソッドが自動的に呼び出されます。

于 2010-02-10T03:03:10.390 に答える
2

匿名メソッドを使用している場合は、ManualResetEvent明らかに便利です。しかし、Sam が述べたように、それらは多くの場合、ワーカーに渡され、設定されて閉じられます。

だから私はそれをどのように使用しているかのコンテキストに依存すると思います.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;
    }
}
于 2010-02-10T11:01:37.413 に答える
2

私はManualResetEvent多くのことを使用してきましたが、単一のメソッド内で使用したことはないと思います。これは常にクラスのインスタンス フィールドです。そのためusing()当てはまらないことが多いです。

のインスタンスであるクラス インスタンス フィールドがある場合は、メソッド呼び出しで および をManualResetEventクラスに実装させます。次に、クラスのすべての使用法で、含まれているクラスを使用または作成し、実装して繰り返し、繰り返す必要があります...IDisposableDispose()ManualResetEvent.Close()using()IDisposable

于 2010-02-10T03:44:12.580 に答える