首页 >后端开发 >C++ >C# 线程可以缓存布尔值并忽略其他线程上的后续更改吗?

C# 线程可以缓存布尔值并忽略其他线程上的后续更改吗?

Susan Sarandon
Susan Sarandon原创
2025-01-05 10:26:44749浏览

Can C# Threads Cache Boolean Values and Ignore Subsequent Changes on Other Threads?

线程上缓存的值可以忽略其他线程上所做的更改吗?

这个问题重点讨论 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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn