首页 > 其他分享 >volatile 关键字

volatile 关键字

时间:2023-06-26 09:23:05浏览次数:34  
标签:关键字 编译器 线程 volatile shouldStop public

原文链接:https://liamw.cn/albums/csharp-dotnet/10-understand-the-volatile-keyword

要理解 C# 中的 volatile 关键字,就要先知道编译器背后的一个基本优化原理。比如对于下面这段代码:

 

public class Example
{
    public int x;
    public void DoWork()
    {
        x = 5;
        var y = x + 10;
        Debug.WriteLine("x = " +x + ", y = " +y);
    }
}

在 Release 模式下,编译器读取 x = 5 后紧接着读取 y = x + 10,在单线程思维模式下,编译器会认为 y 的值始终都是 15。所以编译器会把 y = x + 10 优化为 y = 15,避免每次读取 y 都执行一次 x + 5。但 x 字段的值可能在运行时被其它的线程修改,我们拿到的 y 值并不是通过最新修改的 x 计算得来的,y 的值永远都是 15

也就是说,编译器在 Release 模式下会对字段的访问进行优化,它假定字段都是由单个线程访问的,把与该字段相关的表达式运算结果编译成常量缓存起来,避免每次访问都重复运算。但这样就可能导致其它线程修改了字段值而当前线程却读取不到最新的字段值。为了防止编译器这么做,你就要让编译器用多线程思维去解读代码。告诉编译器字段的值可能会被其它线程修改,这种情况不要使用优化策略。而要做到这一点,就需要使用 volatile 关键字。

给类的字段添加 volatile 关键字,目的是告诉编译器该字段的值可能会被多个独立的线程改变,不要对该字段的访问进行优化。

使用 volatile 可以确保字段的值是可用的最新值,而且该值不会像非 volatile 字段值那样受到缓存的影响。好的做法是将每个可能被多个线程使用的字段标记为 volatile,以防止非预期的优化行为。

为了加深理解,我们来看一个实际的例子:

public class Worker
{
    private bool _shouldStop;

    public void DoWork()
    {
        bool work = false;
        // 注意:这里会被编译器优化为 while(true)
        while (!_shouldStop)
        {
            work = !work; // do sth.
        }
        Console.WriteLine("工作线程:正在终止...");
    }

    public void RequestStop()
    {
        _shouldStop = true;
    }
}

public class Program
{
    public static void Main()
    {
        var worker = new Worker();

        Console.WriteLine("主线程:启动工作线程...");
        var workerTask = Task.Run(worker.DoWork);

        // 等待 500 毫秒以确保工作线程已在执行
        Thread.Sleep(500);

        Console.WriteLine("主线程:请求终止工作线程...");
        worker.RequestStop();

        // 待待工作线程执行结束
        workerTask.Wait();
        //workerThread.Join();

        Console.WriteLine("主线程:工作线程已终止");
    }
}

在这个例子中,while (!_shouldStop) 会被编译器优化为 while(true)。我们可以看一下实际的运行效果来验证这一点。切换 Release 模式,按 Ctrl + F5 运行程序,运行效果始终如下:

程序运行后,虽然主线程在 500 毫秒后执行 RequestStop() 方法修改了 _shouldStop 的值,但工作线程始终都获取不到 _shouldStop 最新的值,也就永远都不会终止 while 循环。

我们修改一下程序,对 _shouldStop 字段加上 volatile 关键字:

public class Worker
{
    private volatile bool _shouldStop;

    public void DoWork()
    {
        bool work = false;
        // 获取的是最新的 _shouldStop 值
        while (!_shouldStop)
        {
            work = !work; // do sth.
        }
        Console.WriteLine("工作线程:正在终止...");
    }

    // ...(略)
}

此时在主线程调用 RequestStop() 方法后,工作线程便立即终止了,运行效果如下图所示:

这说明加了 volatile 关键字后,程序可以实时读取到字段的最新值。

注意,一定要切换为 Release 模式运行才能看到 volatile 发挥的作用,Debug 模式下即使添加了 volatile 关键字,编译器也是不会执行优化的。

当然,并不是所有的类型都可以使用 volatile 关键字修饰的,常见的使用 volatile 的类型是这些简单类型:sbyte, byte, short, ushort, int, uint, char, float 和 bool,其它的请查看参考链接

标签:关键字,编译器,线程,volatile,shouldStop,public
From: https://www.cnblogs.com/ZGXF/p/17504479.html

相关文章

  • C语言里面那些你必须知道的常用关键字(详细讲解)
    前言  哈喽,各位铁汁们好啊!✨今天来给大家带来的是C语言中我们常用的关键字静态static的详细讲解和typedef、#define定义常量和宏。  既然是详解想必大家必定是想学一些平常学不到的东西吧!这里博主给大家详细讲解static修饰的变量在内存重视如何存储的,顺带给大家讲一下C/C++......
  • C++面试八股文:override和finial关键字有什么作用?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第22面:(二师兄好苦逼,节假日还在面试。。。)面试官:C++的继承了解吗?二师兄:(不好意思,你面到我的强项了。。)了解一些。面试官:什么是虚函数,为什么需要虚函数?二师兄:虚函数允许在基类中定义一个函数,然后在派生类中进行重写(override)。二......
  • 基础知识-关键字
    资料参考2021年计算机组成原理考研复习指导|王道考研【重学计算机】计算机组成原理|cnblogs|闪客sun2021年操作系统考研复习指导|王道考研【重学计算机】计算机操作系统|cnblogs|闪客sun计算机组成原理可以在计算机中直接执行的语言和用助记符编写的语言是(机器......
  • ABAP MESSAGE 关键字的使用方法
    ABAPmessage关键字的作用是要么显示在当前用户的登录语言中,从数据库表T100的msg字段中指定的短消息文本,要么显示作为消息的任何文本。以下是可用的变体:如果没有指定RAISING或INTO中的任何一个,语句MESSAGE将中断程序流并发送消息。该语句MESSAGE的基本形式的确切行为(即文本......
  • C++面试八股文:了解auto关键字吗?
    C++面试八股文:了解auto关键字吗?某日二师兄参加XXX科技公司的C++工程师开发岗位第15面:面试官:了解auto关键字吗?二师兄:嗯,了解一些(我很熟悉)。面试官:说一说auto的用法吧?二师兄:auto主要是为了编译器进行类型推导。比如:autoi=42; //i被推导位int型std::vector<int>vi......
  • Linux 如何在 vi 里搜索关键字
    当你用vi打开一个文件后,因为文件太长,如何才能找到你所要查找的关键字呢? 在vi里可没有菜单-〉查找 不过没关系,你在命令模式下敲斜杆(/)这时在状态栏(也就是屏幕左下脚)就出现了“/”然后输入你要查找的关键字敲回车就可以了。 如果你要继续查找此关键字,敲字符n就可以继续查找......
  • Go语言中的defer关键字
    在Go语言中,defer关键字是一个独特而强大的特性,它可以将代码块推迟到函数返回之前执行。这种机制可以用于资源的释放、错误处理、性能优化等多种场景。本文将详细介绍defer的用法和工作原理,并通过实际示例来展示其在不同情况下的应用。defer的基本用法在Go语言中,使用defer关键字......
  • Const 关键字 与指针
    Const关键字与指针发表于2007年04月29日由不及格的程序员-八神星期一天气:晴 使用指针会涉及到两个对象一个是指针本身,另一个是它指向的对象.将指针声明为const就使对象为常量而不是指针为常量;例如:constchar*p="asdf";//指向常量的指针p[2]=‘d’; /......
  • C++ 关键字四种cast类型转换
    1.23四种cast类型转换作用:克服c中强制类型转化带来的风险,C++引入四种更加安全的强制类型转换运算符(明确转换的目的,偏于程序的维护和分析)const_cast://1.去除const属性,将只读变为只读写//2.针对常量指针、常量引用和常量对象constchar*p;char*p1=const_cast<char*>(p......
  • 前端学习C语言 - 函数和关键字
    函数和关键字本篇主要介绍:自定义函数、宏函数、字符串处理函数和关键字。自定义函数基本用法实现一个add()函数。请看示例:#include<stdio.h>//自定义函数,用于计算两个整数的和intadd(inta,intb){//a,b叫形参intsum=a+b;returnsum;}intma......