线程上缓存的值可以忽略其他线程上所做的更改吗?
这个问题重点讨论 C# 线程是否可以缓存值并忽略随后在不同线程上对该值进行了更改。尽管关于竞争条件、原子性和锁的使用等常识,该查询特别针对 .NET 运行时可能抽象出易失性内存问题的场景。
一些消息来源声称,在以下代码中,读取线程可能会“停止”缓存 bool 变量的初始值,并且永远不会检测到其修改,这可能会导致无限循环:
class BackgroundTaskDemo { private bool stopping = false; static void Main() { BackgroundTaskDemo demo = new BackgroundTaskDemo(); new Thread(demo.DoWork).Start(); Thread.Sleep(5000); demo.stopping = true; } static void DoWork() { while (!stopping) { // Do something here } } }
但是,此声明的有效性是有争议。批评者质疑 .NET 运行时是否真的会像所声称的那样忽略内存值的更改。他们指出给定的代码“几乎肯定”有效,这意味着该声明是没有根据的。
问题的关键在于声明中描述的行为不受 .NET 规范的保证。虽然它在大多数情况下可能有效,但不能保证在所有情况下都有效。内存模型领域的专家警告不要依赖这种不可靠的结果。
此外,还提出了一个可验证的反例,演示了代码按预期失败的特定场景。在以下修改后的代码中,“stopping”被声明为 volatile 以纠正该问题:
using System.Threading; using System; static class BackgroundTaskDemo { // make this volatile to fix it private static bool stopping = false; static void Main() { new Thread(DoWork).Start(); Thread.Sleep(5000); stopping = true; Console.WriteLine("Main exit"); Console.ReadLine(); } static void DoWork() { int i = 0; while (!stopping) { i++; } Console.WriteLine("DoWork exit " + i); } }
当在没有 volatile 关键字的“release”模式下运行时,代码会进入无限循环并无限期地继续运行,即使“停止”已设置为 true 后。但是,在“停止”变量中添加“易失性”可以解决该问题,使循环按预期退出。
结论是,虽然代码通常看起来可以正常运行,但不能保证能够正常运行始终如一。对于健壮且可靠的多线程代码,强烈建议使用锁或 volatile 关键字。
以上是C# 线程可以缓存布尔值并忽略其他线程上的后续更改吗?的详细内容。更多信息请关注PHP中文网其他相关文章!