给出一个非常常见的线程场景:
声明
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
仅适用于预期结束并报告状态的程序?
答案 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