2

我有一些场景,我需要一个主线程来等待,直到一组可能的超过 64 个线程中的每一个都完成了它们的工作,为此我编写了以下帮助程序实用程序,(以避免 64 个等待句柄限制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

我不是 C# 或 .NET 程序员,但您可以使用在您的一个工作线程退出时发布的信号量。监视线程将简单地等待信号量n次,其中n是工作线程的数量。信号量传统上用于计算正在使用的资源,但它们可用于通过在同一信号量上等待n次来计算完成的作业。

于 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 回答