ManualResetEvent和CancellationToken停止线程,直到完成其他操作

时间:2019-02-16 13:17:09

标签: c# multithreading

我有一个函数,该函数将同时由5个线程处理,但会传递不同的参数。我想等待使主线程等待其余线程,然后释放它。我什至不确定CancellationToken是否可以与Threadpool一起使用,因为所有示例都与Tasks一起使用,并且我想设置一个按钮以在某个时刻停止线程。

我知道有很多关于线程的信息,但这是实际的问题。我不知道哪个线程类更好或者如何实现它们,因为存在歧义的示例。一位消息人士说,应该以一种方式完成,而以另一种方式完成。这是我看到的一些示例。您可以看到,与其他2个链接相比,MSDN的示例是模棱两可的,或者至少我没有提到这一点。 https://jeremylindsayni.wordpress.com/2016/03/26/how-to-use-manualresetevent-in-c-to-block-one-thread-until-another-has-completed/How to make main thread to wait until other threads endshttps://docs.microsoft.com/en-us/dotnet/api/system.threading.manualresetevent?view=netframework-4.7.2

private void DoJob(object state)
{
    Console.WriteLine("Delaying...");
    Thread.Sleep(3000);
    Console.WriteLine("Thread done");
    _manualResetEvent.Set();
}

// on some button click event
_manualResetEvent = new ManualResetEvent(false);

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}

_manualResetEvent.WaitOne();

Console.WriteLine("Main thread released");

在上面的示例中,我想让主线程等待其余线程,直到它们完成,但是在第一个线程完成之后主线程将被释放。

Delaying...
Delaying...
Delaying...
Delaying...
Thread done
Main thread released
Thread done
Thread done
Thread done

如果我将WaitOne放入每个线程(DoJob方法)中,并将Set放入当前的WaitOne位置,则首先释放主线程,而我想要的是在所有其他线程之后释放它完成。

1 个答案:

答案 0 :(得分:2)

就您而言,您实际上只是使用任务:

var tasks = new List<Task>();

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    tasks.Add(Task.Run(() => DoJob(i)));
}

Task.WaitAll(tasks);

如果由于某种原因您不想使用任务,可以看看CountdownEvent,它专门用于等待一定数量的异步操作:

private void DoJob(object state)
{
    Console.WriteLine("Delaying...");
    Thread.Sleep(3000);
    Console.WriteLine("Thread done");
    _countdownEvent.Signal();
}

// on some button click event
_countdownEvent = new CountdownEvent(threadsNumericUpDown.Value);

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}

_countdownEvent.Wait();

Console.WriteLine("Main thread released");