代码之家  ›  专栏  ›  技术社区  ›  AngryHacker

等待所有线程完成的有用模式是什么?

  •  2
  • AngryHacker  · 技术社区  · 14 年前

    做这类工作的公认模式是什么?是不是很简单,加入?还是现在有更高层次的抽象?

    4 回复  |  直到 14 年前
        1
  •  4
  •   Reed Copsey    14 年前

    在.NET3.5sp1或.NET4中 TPL

    有两种选择。使用Thread.Join是完全可以接受的,尤其是当线程都是您手动创建的线程时。这是非常容易、可靠和易于实现的。这可能是我的选择。

    class MyClass {
        int workToComplete; // Total number of elements
        ManualResetEvent mre; // For waiting
    
        void StartThreads()
        {
            this.workToComplete = 100;
            mre = new ManualResetEvent(false);
    
            int total = workToComplete;
            for(int i=0;i<total;++i)
            {
                 Thread thread = new Thread( new ThreadStart(this.ThreadFunction) );
                 thread.Start(); // Kick off the thread
            }
    
            mre.WaitOne(); // Will block until all work is done
        }
    
        void ThreadFunction()
        {
            // Do your work
    
            if (Interlocked.Decrement(ref this.workToComplete) == 0)
                this.mre.Set(); // Allow the main thread to continue here...
        }
    }
    
        2
  •  1
  •   woo    14 年前

    你看过ThreadPool吗?看起来像这里- ThreadPool tutorial ,avtor按您的要求解决相同的任务。

        3
  •  1
  •   Ed Power    14 年前

    对我来说,最有效的方法是在启动时将每个线程的ManagedThreadId存储在字典中,然后让每个线程在完成时通过回调方法将其id传递回。回调方法从字典中删除id并检查字典的Count属性;当它为零时,你就完成了。确保在添加和删除字典时锁定字典。

        4
  •  1
  •   jrista    14 年前

    我不确定任何类型的标准线程锁定或同步机制是否真的能与这么多线程一起工作。但是,在这种情况下,一些基本的消息传递可能是解决问题的理想方案。

    与使用Thread.Join(它将阻塞(并且可能很难管理这么多线程)不同,您可以尝试再设置一个线程来聚合来自工作线程的完成消息。当聚合器收到所有预期消息时,它将完成。然后,可以在聚合器和主应用程序线程之间使用一个WaitHandle来表示所有工作线程都已完成。

    public class WorkerAggregator
    {
        public WorkerAggregator(WaitHandle completionEvent)
        {
            m_completionEvent = completionEvent;
            m_workers = new Dictionary<int, Thread>();
        }
    
        private readonly WaitHandle m_completionEvent;
        private readonly Dictionary<int, Thread> m_workers;
    
        public void StartWorker(Action worker)
        {
            var thread = new Thread(d =>
                {
                    worker();
                    notifyComplete(thread.ManagedThreadID);
                }
            );
    
            lock (m_workers)
            {
                m_workers.Add(thread.ManagedThreadID, thread);
            }
    
            thread.Start();
        }
    
        private void notifyComplete(int threadID)
        {
            bool done = false;
            lock (m_workers)
            {
                m_workers.Remove(threadID);
                done = m_workers.Count == 0;
            }
    
            if (done) m_completionEvent.Set();
        }
    }