等待线程完成

5
    private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 15; i++)
        {
            Thread nova = new Thread(Method);
            nova.Start();
        }
        listBox1.Items.Add("Some text");
    }

    private void Method()
    {
        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(i);
        }

    }

这段代码会输出:Some text and then numbers 111222333.....

我希望它能够先输出 111122223333....,最后再输出 Some text。

使用线程(父线程等待子线程)可以实现吗?还是需要使用其他方式?


你为什么要使用线程?我猜这只是一个编造的例子,但我需要更多信息才能给你一个准确的答案。 - Matthew Brubaker
可能是重复的问题:C#:等待所有线程完成 - Alan
不,这只是一个例子。我需要访问未知数量的网页。它们都读取相同的信息并将其存储在数据库中。因此,当所有线程完成时,我需要对该信息执行某些操作。在我获得所需的所有信息之前,我无法做任何事情。 - Car90
4个回答

16

你需要跟踪所有线程,并在每个线程上使用Thread.Join。这将等待指定的线程终止,然后继续执行。像这样:

var threads = new List<Thread>();
for (int i = 0; i < 15; i++)
{
    Thread nova = new Thread(Method);
    nova.Start();
    threads.Add(nova);
}
foreach (var thread in threads)
    thread.Join();
listBox1.Items.Add("Some text");

10

我建议使用TPL来完成这个任务。您不需要生成那么多线程。默认情况下,TPL会使用线程池:

using System;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private const int TaskCount = 15;

        static void Main(string[] args)
        {
            var tasks = new Task[TaskCount];
            for (var index = 0; index < TaskCount; index++)
            {
                tasks[index] = Task.Factory.StartNew(Method);
            }
            Task.WaitAll(tasks);

            Console.WriteLine("Some text");
        }

        private static void Method()
        {
            for (int i = 0; i < 15; i++)
            {
                Console.WriteLine(i);
            }
        }
    }
}

1

你可以有两个线程,第二个线程等待来自第一个线程的信号触发。

private void Foo()
{
  var signals = new List<ManualResetEvent>();

  for (int i = 0; i < 15; i++)
  {
    var signal = new ManualResetEvent(false);
    signals.Add(signal);
    var thread = new Thread(() => { Method(); signal.Set(); });
    thread.Start();
  }

  var completionTask = new Thread(() =>
  {
    WaitHandle.WaitAll(signals.ToArray());
    CompletionWork();
  });
  completionTask.Start();

}

private void Method()
{
}

private void CompletionWork()
{
}

现在使用 .Net 4.0(及更高版本)的更好解决方案是使用 Tasks,并使用 ContinueWith 调用方法。
private void Foo()
{
  var childThreads = new List<Task>();
  for (int i = 0; i < 15; i++)
  {
    var task = new Task(Method);
    task.Start();
    childThreads.Add(task);
  }

  var completionTask = new Task(() => 
  { 
    Task.WaitAll(childThreads.ToArray());
  }).ContinueWith(t => CompletionWork());

}

private void Method()
{
}

private void CompletionWork()
{
}

使用join方法也可以,但需要阻塞包含的线程。如果不想让GUI阻塞,请在第一个线程周围生成另一个线程。


在ManualResetEvent的示例中,您似乎没有向信号列表中添加任何内容。它将是空的。 - Garr Godfrey
@GarrGodfrey将该信号添加到了信号列表中,感谢。 - payo

0

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