2

64 を超える可能性のある一連のスレッドのすべてが作業を完了するまで待機するメイン スレッドが必要なシナリオがあり、そのために次のヘルパー ユーティリティを作成しました (64 の waithandle 制限を回避するためWaitHandle.WaitAll()) 。

    public static void WaitAll(WaitHandle[] handles)
    {
        if (handles == null)
            throw new ArgumentNullException("handles",
                "WaitHandle[] handles was null");
        foreach (WaitHandle wh in handles) wh.WaitOne();
    }

ただし、このユーティリティメソッドでは、配列内の先行するすべての待機ハンドルが通知された後にのみ各待機ハンドルが検査されます...したがって、事実上同期であり、待機ハンドルが autoResetEvent 待機ハンドルである場合は機能しません (これは、待機中のスレッドが解放されました)

この問題を解決するために、このコードを次のように変更することを検討していますが、他の人にそれが機能するように見えるかどうか、または誰かがそれに問題があるかどうか、またはより良い方法を提案できるかどうかを確認してもらいたいです...

前もって感謝します:

    public static void WaitAllParallel(WaitHandle[] handles)
    {
        if (handles == null)
            throw new ArgumentNullException("handles",
                "WaitHandle[] handles was null");
        int actThreadCount = handles.Length;
        object locker = new object();
        foreach (WaitHandle wh in handles)
        {
            WaitHandle qwH = wh;
            ThreadPool.QueueUserWorkItem(
                 delegate
                 {
                     try { qwH.WaitOne(); }
                     finally { lock(locker) --actThreadCount; }
                 });
        }
        while (actThreadCount > 0) Thread.Sleep(80);
    }
4

5 に答える 5

3

スレッド数がわかっている場合は、インターロック デクリメントを使用できます。これは私が通常行う方法です:

 {
 eventDone = new AutoResetEvent();
 totalCount = 128;
 for(0...128) {ThreadPool.QueueUserWorkItem(ThreadWorker, ...);}
 }

 void ThreadWorker(object state)
 try
 {
   ... work and more work
 }
 finally
 {
   int runningCount = Interlocked.Decrement(ref totalCount);
   if (0 == runningCount)
   {
     // This is the last thread, notify the waiters
     eventDone.Set();
   }
 }

実際、ほとんどの場合、シグナルを送ることさえしませんが、代わりにコールバックを呼び出して、ウェイターが続行する場所から処理を続行します。ブロックされたスレッドが少なくなり、スケーラビリティが向上します。

私は異なることを知っており、あなたのケースには当てはまらないかもしれません (たとえば、ハンドルの一部がスレッドではなく、I/O またはイベントである場合は確実に機能しません)が、これについて考える価値があるかもしれません。

于 2009-12-30T21:38:36.403 に答える
2

あなたが何をしようとしているのか正確にはわかりませんが、CountdownEvent (.NET 4.0) は概念的に問題を解決しますか?

于 2009-12-30T21:38:27.453 に答える
1

I'm not a C# or .NET programmer, but you could use a semaphore that is posted when one of your worker threads exits. The monitoring thread would simply wait on the semaphore n times where n is the number of worker threads. Semaphores are traditionally used to count resources in use but they can be used to count jobs completed by waiting on the same semaphore for n times.

于 2009-12-30T21:56:41.707 に答える
0

多数の同時スレッドを操作する場合、スレッドの開始時に各スレッドの ManagedThreadId をディクショナリに追加し、各スレッドにコールバック ルーチンを呼び出して、死にかけているスレッドの ID をディクショナリから削除することを好みます。Dictionary の Count プロパティは、アクティブなスレッドの数を示します。キーと値のペアの値側を使用して、UI スレッドがステータスを報告するために使用できる情報を保持します。物事を安全に保つために、ディクショナリをロックでラップします。

于 2010-01-03T23:15:11.583 に答える
-1
ThreadPool.QueueUserWorkItem(o =>
{
    try
    {
        using (var h = (o as WaitHandle))
        { 
            if (!h.WaitOne(100000))
            {
                // Alert main thread of the timeout
            }
        }
    }
    finally
    {
        Interlocked.Decrement(ref actThreadCount);
    }
 }, wh);
于 2009-12-30T21:30:19.027 に答える