我正在编写一个包含几个线程的程序,每个程序都有一个while循环,直到用户指定它应该停止。我想到了退出循环的几种方法,以及随后的线程,并在下面概述了这些方法。
问题
以下是方法。
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可能会更好(因为您可以根据自己的内容设置和重置)。
答案 0 :(得分:2)
大多数情况下,你的线程不会在紧凑的循环中运行,占用你所有的CPU周期,通常你在等待某种事件,当你等待时你不能真正等待一个bool。您可以在事件中超时,等待超时,检查bool,然后返回等待。这会产生令人讨厌的代码,也意味着你的线程不会在超时发生之前退出,或者你让你吃CPU检查一个bool。
重置事件没问题,你当然可以使用它,但是CancelellationToken运行良好,并且正是为此而设计的。