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

时间:2010-02-18 18:25:40

标签: c# visual-studio-2008 multithreading design-patterns .net-2.0

我有一个场景,我将不得不开始大量的线程(可能达到100),然后等待它们完成,然后执行任务(在另一个线程上)。

进行此类工作的可接受模式是什么?它只是.Join?或者现在是否有更高级别的抽象?

将.NET 2.0与VS2008结合使用。

4 个答案:

答案 0 :(得分:4)

在.NET 3.5sp1或.NET 4中,TPL会使这更容易。但是,我将仅针对.NET 2功能进行定制。

有几种选择。使用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...
    }
}

答案 1 :(得分:1)

你看过ThreadPool了吗?看起来像这里 - ThreadPool tutorial,avtor解决了你提出的相同任务。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

我不确定任何类型的标准线程锁定或同步机制是否真的适用于这么多线程。但是,这可能是一些基本消息传递可能是解决问题的理想方案。

您可能会尝试再设置一个聚合来自工作线程的完成消息的线程,而不是使用会阻塞(并且可能很难用这么多线程管理)的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();
    }
}

注意,我没有测试过上面的代码,所以它可能不是100%正确。但是我希望它能够说明这个概念足够有用。