此问题探讨了 C# 线程行为中的潜在异常,与竞争条件或锁需求无关。具体来说,问题在于线程是否可以缓存某个值并忽略其他线程上对该值所做的更改,从而可能导致意外行为。
管理内存的 NET 运行时被认为可以缓解此问题。然而,一些文献另有说法,断言某些代码结构(如下所示)可能会导致无限循环:
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 } } }
根据引用的文章(http://www.yoda.arachsys.com/ csharp/threads/volatility.shtml , http://softwareengineering.stackexchange.com/questions/104757/is-a-string-property-itself-threadsafe),读取线程可能会缓存停止变量的初始值,使所有后续更新不可见并导致线程无限期地运行。
但是,内存建模专家坚持认为 C# 规范不保证这种行为。虽然提供的代码通常可以正确运行,但它依赖于特定于平台和编译器的优化,而不是具体的语言语义。
为了进一步说明该问题,请考虑以下修改后的代码:
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); } }
通过此修改,代码可以预见地输出“Main exit”,但 DoWork 方法会无限期地继续运行。这个反例表明,尽管最初有怀疑,C# 运行时并不总是保证跨线程值更新的一致性。
为了解决这种歧义,可以将 volatile 关键字应用于停止变量。易失性修饰符强制对变量进行原子访问,防止缓存的值掩盖实际更新。
以上是C# 线程可以忽略其他线程的值更改吗?的详细内容。更多信息请关注PHP中文网其他相关文章!