首页 > 其他分享 >c volatile一文搞懂

c volatile一文搞懂

时间:2023-08-04 13:23:06浏览次数:27  
标签:一文 原子 线程 操作 volatile 搞懂 多线程 变量

关键字

volatile

简单来说就两个作用:

  1. 保证不被编译器优化

    例如重复的赋值

    volatile int value = 10;
    value = 10;
    value = 10;
    

    volatile修饰后,一是这几个语句都会得到执行,二是顺序不会改变

  2. 保证可见性

    这里可见性的意思是,在多线程的环境下,当一个线程对一个变量改变,另一个线程能够知道当前的值已经改变,即:可见性的变量,在cpu改变他的值后,会立即写入内存中,而不是停留在cpu的cach中(基本cpu读写变量不是直接读写,而是缓存在cach中,有时cpu运算数据会直接读写到cach上,不能够及时写入内存)。

    可见,虽然volatile能够保证可见性,但是不能保证操作的原子性,原因如下:

    原子操作要求不能打断整个操作流程,但volatile修饰的变量可以在其他线程被改变。要保证原子性需要添加相关机制如:自旋锁。

链接:

  1. 内核中为什么不应该使用volatile关键字

    https://lp007819.wordpress.com/2013/01/20/%E5%86%85%E6%A0%B8%E4%B8%AD%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BD%BF%E7%94%A8volatile%E5%85%B3%E9%94%AE%E5%AD%97/
    
  2. ​ chat_gpt问答:

    为什么定义了volatile还是不能保证原子操作
    ChatGPT
    定义了 volatile 只能保证对变量的读写操作是可见的,并且编译器不会对访问该变量的指令进行优化,但它不能保证原子操作。原子操作是指在多线程环境下,一个操作要么完全执行成功,要么完全不执行,没有中间状态,不会被其他线程打断。
    
    虽然 volatile 告诉编译器不要优化对该变量的访问,但在多线程环境中,仍然可能发生并发问题。例如,如果多个线程同时对同一个 volatile 变量进行自增操作,由于没有加锁或其他同步机制,可能会出现竞争条件,导致结果不是预期的。这时候,volatile 不能保证原子性,因为多个线程之间可能会同时读取、修改和写回变量,而不考虑其他线程的操作。
    
    要实现原子操作,需要使用其他同步机制,比如使用互斥锁(mutex)、原子操作库或并发容器。这些机制可以确保在多线程环境下,某个特定代码块或操作只能被一个线程执行,从而保证原子性和线程安全性。
    
    总结:volatile 只能保证可见性和禁止编译器优化,但不能保证原子操作。要实现原子操作和线程安全性,需要使用其他同步机制来确保在多线程环境中操作的原子性。
    
    
    
    
    User
    这里的读写可见性是是什么意思
    ChatGPT
    在多线程编程中,可见性是指一个线程对共享变量的修改能够被其他线程及时看到的特性。当一个线程修改了某个共享变量的值,其他线程在之后访问该变量时能够看到最新的值,而不是之前缓存的旧值。
    
    可见性问题主要涉及到多线程之间的内存可见性。现代计算机体系结构中,每个线程都有自己的缓存(CPU cache),这些缓存用于加快对内存的访问速度。当一个线程对共享变量进行修改时,它首先会将修改后的值存储在自己的缓存中,并且在合适的时机将这个修改刷新到主内存中。其他线程在访问这个共享变量时,可能会直接从自己的缓存中读取值,而不是从主内存中读取。这就可能导致多个线程之间看到的是不一致的值,即出现了内存可见性问题。
    
    为了解决内存可见性问题,可以使用同步机制,如互斥锁(mutex)或原子操作,来确保对共享变量的读写是原子的,从而保证修改的可见性。当一个线程获取了锁或执行了原子操作时,其他线程必须等待,直到这个操作完成,从而保证了对共享变量的读写操作对其他线程是可见的。
    
    volatile 关键字也提供了可见性的保证。当一个变量被声明为 volatile 时,对该变量的写操作会立即刷新到主内存,而对该变量的读操作会从主内存中获取最新的值。这样可以保证多线程之间对该变量的修改对其他线程是可见的。
    
    总结:可见性是指多线程之间对共享变量修改的可见性。为了保证可见性,需要使用同步机制或 volatile 关键字来确保对共享变量的读写操作是原子的,并及时刷新到主内存,从而保证其他线程能够看到最新的值。
    
    
    
    
    User
    在这里,既然已经保证可见性了,那为什么还不能保证是原子操作
    ChatGPT
    您是正确的,我之前的回答有一点混淆。在多线程编程中,volatile 关键字主要用于保证可见性,但它并不能保证原子操作。
    
    当一个变量被声明为 volatile 后,对该变量的写操作会立即刷新到主内存,而对该变量的读操作会从主内存中获取最新的值,确保了多个线程之间对变量值的可见性。这意味着当一个线程修改了 volatile 变量的值,其他线程可以立即看到最新的值,而不是过期的缓存值。
    
    然而,volatile 关键字并不能保证原子操作。原子操作是指一个操作要么完全执行成功,要么完全不执行,没有中间状态。在多线程环境中,多个线程同时对同一个变量进行读写操作时,仍然可能出现竞争条件和数据不一致的问题。即使对一个 volatile 变量进行自增或自减操作,在高并发情况下,多个线程同时读取并修改该变量,可能导致结果不是预期的。
    
    要实现原子操作,需要使用其他同步机制,比如使用互斥锁(mutex)、原子操作库或并发容器。这些机制可以保证在多线程环境下,某个特定代码块或操作只能被一个线程执行,从而保证了原子性和线程安全性。
    
    因此,volatile 关键字在多线程编程中主要用于保证对变量的可见性,而不是用于实现原子操作。要实现原子操作,需要使用其他同步手段来确保操作的原子性。
    

    转载请附本文链接

标签:一文,原子,线程,操作,volatile,搞懂,多线程,变量
From: https://www.cnblogs.com/langdaodao/p/17605627.html

相关文章

  • 第四天——搞懂问题
    问题1:#include<stdio.h>和#include"stdio.h"有什么区别?1、#include<>一般用于包含系统头文件,诸如stdlib.h、stdio.h、iostream等;2、#include""一般用于包含自定义头文件,比如我们自定义的test.h、declare.h等。'这是因为:查找范围不同:""会优先查找自己项目工程下文件,查......
  • 带你来吃瓜!Andy Pavlo教授带您一文回顾数据库的2022年
    <br>:::hljs-right编辑/翻译:宇亭校对:王学姣、李浩:::<br>本文是由数据库界知名专家AndyPavlo教授写的2022年数据库回顾文章,这个系列从去年开始,非常经典,也比较系统的整理了一下数据库界的大事件(当然,主要还是以国外的居多),StoneDB团队对本文进行了翻译,小编在一些链接部分加......
  • volatile关键字剖析
    这里引入一个案例:实现单例模式的双重检查锁packagecom.chunling.cloud.test;publicclassSingleton{privatestaticSingletoninstance;privateintvalue;privateSingleton(){try{Thread.sleep(100);}catch(Interrupted......
  • 稳扎稳打,坚定前行 | 一文带你回顾 StoneDB 的 2022 年
    2022年6月29号,StoneDB正式宣布开源,自开源以来,StoneDB开源团队在用心打磨产品的同时,也在积极地拥抱开源社区,与万千数据库开发者共同成长,我们从day1就励志要做一款立足中国、面向全球的开源数据库,内核代码已经在Github上完全开源,欢迎大家前往关注:https://github.com/sto......
  • 实用干货!一文读懂Salesforce中6种数据关系类型!
    Salesforce中对象之间的数据关系可能是一个棘手的话题。对于创建自定义对象的业务场景,需要决定使用哪些关系类型来扩展Salesforce数据模型。01查找关系查找关系(LookupRelationships)是一种松散耦合(looselycoupled)的关系,允许以一对多的方式将一个对象连接到另一个对象。它是在......
  • 彻底搞懂Java中的Runnable和Thread
    写在前面今天在阅读ThreadPoolExecutor源码的时候觉得有些地方理解起来似是而非,很别扭!最后才猛然发现,原来是我自己的问题:没有真正理解Runnable和Thread的含义!我之前对于Runnable和Thread理解的误区在于:“Runnble和Thread是实现多线程的两种方式,在Java中要实现多线程运行要么实现......
  • 一文搞懂什么是零拷贝
    引言在计算机领域,数据传输和存储一直是重要的优化方向。而零拷贝(ZeroCopy)技术因其高效、节能等优势备受关注。本文将深入解析零拷贝的原理、优势以及具体的实现方式,助您全面了解这项令人惊叹的技术。什么是零拷贝?零拷贝(Zero-Copy)是一种高效的数据传输技术,它可以将数据从内核......
  • 一文让你彻底掌握ThreadLocal
    本文分享自华为云社区《【高并发】一文带你彻底搞懂ThreadLocal》,作者:冰河。我们都知道,在多线程环境下访问同一个共享变量,可能会出现线程安全的问题,为了保证线程安全,我们往往会在访问这个共享变量的时候加锁,以达到同步的效果,如下图所示。对共享变量加锁虽然能够保证线程的安全,但......
  • 一文让你彻底掌握ThreadLocal
    本文分享自华为云社区《【高并发】一文带你彻底搞懂ThreadLocal》,作者:冰河。我们都知道,在多线程环境下访问同一个共享变量,可能会出现线程安全的问题,为了保证线程安全,我们往往会在访问这个共享变量的时候加锁,以达到同步的效果,如下图所示。对共享变量加锁虽然能够保证线程的安......
  • 教你一文教你使用自己的域名远程访问内网群晖NAS+6.X【内网穿透】
    文章目录使用自己的域名远程访问内网群晖NAS6.X【内网穿透】使用自己的域名远程访问内网群晖NAS6.X【内网穿透】在之前的文章中,我们向大家演示了如何使用cpolar,创建一条固定的、能够在公共互联网登录内网群晖NAS的数据隧道。这条隧道已经能够应对大多数情况。不过我们能看到,在......