C# 什么';等待所有线程完成的有效模式是什么?

C# 什么';等待所有线程完成的有效模式是什么?,c#,visual-studio-2008,multithreading,design-patterns,.net-2.0,C#,Visual Studio 2008,Multithreading,Design Patterns,.net 2.0,我有一个场景,我必须启动大量线程(可能最多100个),然后等待它们完成,然后执行一个任务(在另一个线程上) 做这类工作的公认模式是什么?是不是很简单,加入?还是现在有更高层次的抽象 将.NET 2.0与VS2008结合使用。您看过ThreadPool吗?看起来,这里-,avtor解决了与您要求的相同的任务。在.NET3.5sp1或.NET4中,将使这更容易。不过,我将仅针对.NET2的功能进行调整 有两种选择。使用Thread.Join是完全可以接受的,尤其是当线程都是您手动创建的线程时。这是非

我有一个场景,我必须启动大量线程(可能最多100个),然后等待它们完成,然后执行一个任务(在另一个线程上)

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


将.NET 2.0与VS2008结合使用。

您看过ThreadPool吗?看起来,这里-,avtor解决了与您要求的相同的任务。

在.NET3.5sp1或.NET4中,将使这更容易。不过,我将仅针对.NET2的功能进行调整

有两种选择。使用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...
    }
}
class-MyClass{
int workToComplete;//元素总数
ManualResetEvent mre;//等待
void StartThreads()
{
此.workToComplete=100;
mre=新手动重置事件(错误);
int total=完成的工作量;

对于(int i=0;i对我来说,最有效的方法是在启动时将每个线程的ManagedThreadId存储在字典中,然后让每个线程在完成时通过回调方法将其id传递回。回调方法从字典中删除id并检查字典的Count属性;当它为零时,您就完成了。请确保在运行时锁定我不确定任何类型的标准线程锁定或同步机制是否真的能与这么多线程一起工作。但是,在这种情况下,一些基本的消息传递可能是解决问题的理想方法

而不是使用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();
    }
}
公共类WorkerAggregator
{
公共WorkerAggregator(WaitHandle completionEvent)
{
m_completionEvent=completionEvent;
m_workers=新字典();
}
私有只读WaitHandle m_completionEvent;
私人只读词典;
公共无效StartWorker(行动工作者)
{
var线程=新线程(d=>
{
工人();
notifyComplete(thread.ManagedThreadID);
}
);
锁(m_工人)
{
添加(thread.ManagedThreadID,thread);
}
thread.Start();
}
私有void notifyComplete(int-threadID)
{
bool done=false;
锁(m_工人)
{
m_工人。移除(螺纹ID);
完成=m_工人。计数==0;
}
如果(完成)m_completionEvent.Set();
}
}

注意,我没有测试上面的代码,因此它可能不是100%正确。但是我希望它能够充分说明这个概念,使其变得有用。

您可以使用并行扩展而不是创建自己的线程吗?waithandle上有64个句柄的限制。waitallYou可以通过在每个元素上按顺序等待WaitOne来完成同样的事情,但是ugh-这允许您使用>64个等待句柄。(也就是说,我更喜欢我的方法…)可能应该向后运行线程开始循环(
for(int I=workToComplete;I>0;--I)
)因此,如果您的ThreadFunction在循环之前完成,则Interlocated.Decrement不会与条件匹配。@Tanzelax:这一点很好。我刚刚在其中引入了一个临时函数来处理它(正确)。捕捉得很好。您需要启动线程(在将其添加到m_workers之后)…它将永远不会运行,如所述。