使用任务的经典永无止境的线程循环?

时间:2013-11-12 13:28:32

标签: c# multithreading asynchronous task-parallel-library

给出一个非常常见的线程场景:

声明

private Thread _thread;
private bool _isRunning = false;

开始

_thread = new Thread(() => NeverEndingProc());
thread.Start();

方法

private void NeverEndingProc() {
    while(_isRunning) {
        do();
    }
}

可能在异步tcp监听器中使用,等待回调,直到它通过让线程用完(_isRunning = false)来停止。

现在我想知道:是否可以用Task做同样的事情?使用CancellationToken?或Task仅适用于预期结束并报告状态的程序?

2 个答案:

答案 0 :(得分:3)

可以当然只需将NeverEndingProc传递给Task.Run即可。

但是,功能上有一个重要的区别:如果异常在NeverEndingProc中从Thread传播出来,则会导致进程崩溃。如果它在Task中,它将引发TaskScheduler.UnobservedException然后被静默忽略(从.NET 4.5开始)。

也就是说,您可以探索其他选择。例如,Reactive Extensions几乎消除了对“无限线程循环”的任何需求。

答案 1 :(得分:1)

使用Task + CancellationToken的一个原因是使各个进程及其取消更加相互独立。在您的示例中,请注意NeverEndingProc如何需要直接引用同一类中的_isRunning字段。相反,您可以接受外部令牌:

开始:

public void StartNeverEndingProc(CancellationToken token) {
    Task.Factory.StartNew(() => NeverEndingProc(token), token);
}

方法:

private void NeverEndingProc(CancellationToken token) {
    while (true) {
        token.ThrowIfCancellationRequested();
        do();
    }
}

现在取消由来电者管理,可以应用于多个独立的任务:

var instance = new YourClass();

var cts = new CancellationTokenSource();

instance.StartNeverEndingProc(cts.Token);  // start your task
StartOtherProc(cts.Token);  // start another task

cts.Cancel();  // cancel both