C# .Net 4.0控制台应用程序 - 如何保持活动状态直到所有线程完成?

6

可能是重复问题:
C#: 等待所有线程完成

我有一个控制台应用程序,它会生成一些线程然后退出。每个线程大约需要 ~20 秒钟才能完成。看起来似乎控制台应用程序在生成线程后立即退出,而没有等待线程完成。

如何告诉控制台应用程序不要退出,直到它生成的所有线程都完成了?


很棒的答案集合。@JohnEgbert - 线程在循环中被生成,所以你的解决方案正是我正在寻找的。虽然我相信其他人也会从提供的解决方案中受益。 - downatone
7个回答

8
你可以使用一个 CountDownEvent
using System;
using System.Collections.Generic;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static CountdownEvent countdown;

        static void Main(string[] args)
        {
            countdown = new CountdownEvent(1);
            for (int i = 1; i < 5; i++)
            {
                countdown.AddCount(); //add a count for each (BEFORE starting thread .. Thanks, Brian!)
                //do stuff to start background thread
            }
            countdown.Signal(); //subtract your initial count
            countdown.Wait(); //wait until countdown reaches zero
            //done!
        }

        static void backgroundwork()
        {
            //work
            countdown.Signal(); //signal this thread's completion (subtract one from count)
        }
    }
}

2
我经常使用这个模式,它非常有效。请注意,在启动线程之前,AddCount 应该真正发生,否则如果第一个线程在调用 AddCount 之前完成,可能会导致事件过早地被触发,从而产生极其微妙的错误。 - Brian Gideon
从未想过,但这种情况确实可能发生。虽然罕见,但排除故障会非常烦人。 - Tim Coker
哈哈,是的,"罕见"这个词可能还不够形容,特别是当线程在执行任何有用的工作时。但是,如果出现这种情况,那肯定会成为一个非常棘手的 bug! - Brian Gideon

6

这个循环是否会产生多个线程?如果是的话,可以使用Parallel.ForEach:

ParallelOptions options = new ParallelOptions();
                    Parallel.ForEach(items, options, item=>
                    {
// Do Work here
                    });

如果您实际上不会设置任何选项,我建议您选择不需要传递ParallelOptions的重载,并完全省略第一行。 - Joel Mueller

3
只要 Thread 不是后台线程 (.IsBackground),该应用程序就应该保持活动状态:
static void Main()
{
    Thread thread = new Thread(MoreStuff);
    thread.IsBackground = false;
    thread.Start();
    Console.WriteLine("Main thread exiting");
}
static void MoreStuff()
{
    Console.WriteLine("Second thread starting");
    Thread.Sleep(5000); // simulate work
    Console.WriteLine("Second thread exiting");
}

不需要其他的东西。请注意,ThreadPool 将使用后台线程; 问题可能是您在此处使用 ThreadPool 吗?

注意:如果第二个线程实际上还没有启动,那么可能会存在一个小的竞争条件,导致它过早地退出;您可能需要对线程的启动进行控制。


2
您可以使用 Thread.Join 等待线程完成。

2

你是如何启动线程的?这要视情况而定,但如果你只是使用Thread类,那么从主线程调用yourThread[i].Join()确保所有线程都完成。

查看任务和任务工厂,可以比以往更清晰地处理事物。


2

在启动线程后,对所有启动的线程调用Thread.Join()。这将阻塞当前线程,直到该线程完成。


0

你应该使用同步并等待任何已生成的线程完成其工作,可以通过使用阻塞主线程的Thread.Join调用或使用信号(例如使用Monitor或其他选项)来实现。

或者,您可以通过设置IsForeground属性(如果我没记错的话)使生成的线程运行为前台线程。这将保持应用程序处于活动状态,直到线程终止,但仍会看到控制台窗口在主线程退出时消失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接