退出/取消跨线程循环的技术:bool,ManualResetEvent或CancellationToken

时间:2014-12-09 23:13:16

标签: c# multithreading cancellation manualresetevent cancellation-token

我正在编写一个包含几个线程的程序,每个程序都有一个while循环,直到用户指定它应该停止。我想到了退出循环的几种方法,以及随后的线程,并在下面概述了这些方法。

问题

  1. 每种都有利弊吗?
  2. 是否有使用一种而非另一种情况的情况?
  3. 我听到有人说他们更喜欢CancellationTokens退出线程。这种方法对其他两种方法有什么吸引力?
  4. 以下是方法。

    bool方法

    最初,我已经宣布了一个bool并且刚刚声明循环一直运行直到用户将bool设置为false:while(running) { Thread.Sleep(10); /*do work*/ }。然后我思索是否完全是线程安全的。如果编译器进行了一些优化并将bool移动到寄存器怎么办?在这种情况下,线程会看到bool的不同值。因此,我使用volatile关键字标记了bool,以避免编译器优化。

    ManualResetEvent方法

    我的下一个方法是创建一个ManualResetEvent,并且只是说当一个WaitOne()为false时,bool会运行:while(!mre.WaitOne(10)) {/*do work*/}。这将阻塞10ms,然后一遍又一遍地运行循环,直到我们执行mre.Set()并且循环退出。

    CancellationToken方法

    这种方法我还没有尝试过,但我读了几个人们更喜欢用这种方式取消线程的地方。它显然是线程安全的。可以定义CancellationTokenSource,将其称为cts,然后将cts.Token传递给新线程运行的方法,并使用if语句检查是否已请求取消:{{1} }

    更新1:

    我发现了一篇类似的帖子,其结论是while(!token.IsCancellationRequested) { Thread.Sleep(10); /*do work*/ }方法明显慢于MRE方法。有关完整信息,请参阅此处:Stopping a Thread, ManualResetEvent, volatile boolean or cancellationToken

    更新2:

    在将CancellationToken方法与其他两种方法进行比较时,Eric Lippert在这里有一个很好的答案:AutoResetEvent vs. boolean to stop a thread

    更新3:

    我发现了另一条相关的信息。取消取消后,取消权限无法重置。因此,当您只想暂时取消循环,以后再次启动它时,它并不理想。为此,MRE可能会更好(因为您可以根据自己的内容设置和重置)。

1 个答案:

答案 0 :(得分:2)

大多数情况下,你的线程不会在紧凑的循环中运行,占用你所有的CPU周期,通常你在等待某种事件,当你等待时你不能真正等待一个bool。您可以在事件中超时,等待超时,检查bool,然后返回等待。这会产生令人讨厌的代码,也意味着你的线程不会在超时发生之前退出,或者你让你吃CPU检查一个bool。

重置事件没问题,你当然可以使用它,但是CancelellationToken运行良好,并且正是为此而设计的。