如何在主线程中终止由Parallel.ForEach创建的所有线程?

4

以下是场景:

我有一个正在运行的Windows服务。在OnStart()方法中,它设置了一个计时器,该计时器将调用一个函数(假设我们称其为ProcessEvent())。ProcessEvent()内部的代码是一个临界区,因此只有一个线程可以执行以下操作:

private void ProcessEvent(object sender, ElapsedEventArgs e)
{
    lock(lockObj)
    {
        string[] list = GetList();
        Parallel.ForEach(list, item => { ProcessItem(item) });
    }
}

ProcessItem 可能需要很长时间。

现在当服务停止时,我的 OnStop() 目前只停止并释放计时器。然而,我注意到即使服务停止后,仍有线程在运行 ProcessItem()

那么,我如何杀死由此程序产生的所有正在运行的线程(主要是由 Parallel.ForEach 产生的线程,但也包括任何在 ProcessEvent 中等待锁的线程)?

我知道如果我自己创建了线程,我可以将 isBackground 设置为 true,当进程结束时它们都会被杀死,但我没有手动创建这些线程。

2个回答

8

使用CancellationToken结构。阅读此文档此文档了解更多信息。

// Setup the cancellation mechanism.
var cts = new CancellationTokenSource();
var po = new ParallelOptions();
po.CancellationToken = cts.Token;

// Run the enumerator in parallel.
Parallel.ForEach(list, po, 
  (item) =>
  {
    ProcessItem(item);
    po.CancellationToken.ThrowIfCancellationRequested();
  });

// Call Cancel to make Parallel.ForEach throw.
// Obviously this must done from another thread.
cts.Cancel();

太好了!虽然我喜欢spender的解决方案,但这个更简洁,因为我不必自己维护标志。 - encee
这个 cts.Cancel() 是取消所有线程还是只取消当前线程,以便它自己被取消? - anmarti
@anmarti:假设代码正确遵循取消协议,它将导致任何正在“监听”它的线程结束自身。 - Brian Gideon

5

查看使用带有ParallelLoopState参数的委托的Parallel.ForEach重载。在循环体中检查标志以确定是否应继续执行,否则终止执行:

Parallel.ForEach(list, (item, pls) => { 
    if(quit)pls.Stop();
    else
        ProcessItem(item);
});

在这种情况下,“quit”是什么?只是我在“OnStop()”中设置的标志吗? - encee
太好了,谢谢!那么定时器生成的线程在ProcessEvent中等待锁定的线程会自动终止吗? - encee
这只是不会启动任何新线程;它对已经启动的线程没有帮助。http://msdn.microsoft.com/en-us/library/dd460721.aspx - Rick Sladkey

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