【问题标题】:Classic never-ending thread loop using tasks?使用任务的经典永无止境的线程循环?
【发布时间】:2013-11-12 13:28:31
【问题描述】:

Given 是一个非常常见的线程场景:

声明

private Thread _thread;
private bool _isRunning = false;

开始

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

方法

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

可能用于异步 tcp 侦听器,该侦听器等待回调,直到通过让线程耗尽而停止 (_isRunning = false)。

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

【问题讨论】:

  • 您只想使用任务创建一个带有取消选项的无限循环?
  • @Deffiss 基本上,是的。我曾经被告知是“只是”线程,但在更高的层次上,它们的行为略有不同,但目的相同。不过,我可能错了。
  • 我认为_isRunning 必须是volatile。否则,编译器可能会意识到它不是从当前线程修改的,并且在循环开始之前只检查一次。

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


【解决方案1】:

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

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

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

【讨论】:

  • TaskCreationOptions.LongRunning 在这里是必要的,不是吗?所以Factory.StartNewTaskCreationOptions 和“DefaultScheduler”将是比Task.Run 更可取的选项。有错请指正
  • Reactive Extensions 听起来很有希望,但目前我没有时间研究另一个新工具。 :)
  • @SriramSakthivel:LongRunning 只是一个提示。除非您在开始“无限循环”任务时已经在进行非常密集的并行处理,否则这是不必要的。而Task.Run 使用默认调度器。
  • @StephenCleary 我不确定您所说的“没有必要”是什么意思。没有那个 ThreadPool 将使用池的线程对吗?启用它会为任务创建专用线程,允许池的线程处理其他小型 cpu 密集型操作?
  • @ErwinMayer:我相信是这样,但我不完全确定。
【解决方案2】:

使用 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

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 2020-03-14
    • 1970-01-01
    相关资源
    最近更新 更多