讲讲volatile的作用

合集下载

volatile 的用法 java

volatile 的用法 java

Volatile 关键字是 Java 中一个非常重要的关键字,它在多线程编程中扮演了重要的角色。

volatile 关键字的作用是告诉编译器,该变量是易变的,可能会被其他线程修改,因此在访问这个变量的时候需要从内存中重新读取,而不是使用缓存中的值。

在本文中,我们将探讨volatile 关键字的用法,并介绍一些 volatile 关键字的相关知识。

一、volatile 关键字的基本用法在Java中,使用 volatile 关键字来声明一个变量,可以确保该变量对所有线程的可见性。

这意味着当一个线程修改了这个变量的值时,其他线程能够立即看到这个变化。

而不使用volatile 关键字声明的变量,在多线程环境下可能会存在可见性问题。

二、volatile 关键字的内存语义在编写多线程程序的时候,我们需要考虑多线程之间的内存可见性和指令重排序的问题。

volatile 关键字可以解决这些问题。

在Java内存模型中,当一个变量声明为 volatile 后,编译器和运行时会对这个变量进行特殊处理,确保在多线程环境下能够正确的执行。

三、volatile 关键字和锁的区别在多线程程序中,通常使用锁来保护共享变量的访问。

但是锁的使用会带来一定的性能损耗,而且容易出现死锁等问题。

与锁相比,volatile 关键字提供了一种更轻量级的线程同步机制。

它能够确保变量的可见性,而不会造成线程阻塞,因此在一些场景下使用 volatile 关键字可能会更加适合。

四、volatile 关键字的适用场景在实际开发中,volatile 关键字通常用于一些标识位的控制或者状态的转换,例如在单例模式中使用 volatile 关键字可以确保单例对象的实例化过程对所有线程可见。

volatile 关键字还常常用于双重检查锁定模式(Double-Checked Locking Pattern)中,确保单例对象的线程安全性。

五、volatile 关键字的注意事项虽然 volatile 关键字能够确保变量的可见性,但是它并不能保证原子性。

c语言 volatile的原理

c语言 volatile的原理

c语言 volatile的原理
C语言中的volatile关键字用于告诉编译器不要对被声明为volatile的变量进行优化,因为这些变量的值可能会在程序的控制之外被改变。

volatile的原理涉及编译器优化和内存访问的问题。

当一个变量被声明为volatile时,编译器会生成对该变量的每次访问代码,以确保对该变量的读写操作不会被优化掉。

这是因为volatile变量的值可能会在程序的执行过程中被外部因素改变,比如硬件中断、多线程环境下的共享变量等。

如果编译器对volatile 变量的读写操作进行优化,可能导致程序出现意外的行为。

另外,volatile还可以用于指针类型。

当一个指针被声明为volatile时,意味着该指针所指向的内存区域的内容可能会在程序的控制之外被修改,因此编译器不应该对通过该指针进行的读写操作进行优化。

在多线程编程中,volatile还可以用于确保线程之间对共享变量的可见性。

在这种情况下,volatile可以告诉编译器不要对共享变量的读写操作进行重排序,以确保线程能够正确地看到其他线程对共享变量的修改。

总之,volatile关键字的原理涉及编译器优化和内存访问的问题,它告诉编译器不要对声明为volatile的变量进行优化,以确保这些变量的读写操作不会被意外地优化掉,从而保证程序的正确性和可靠性。

嵌入式开发-c语言中volatile关键字作用

嵌入式开发-c语言中volatile关键字作用

volatile 就是在此种情况下使用。
16
C 语言中 语言中 volatile 关键字作用 关键字作用 一个定义为 volatile 的变量是说这变量可能会被意想不到地改变,这样,编 译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必 须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下 面是 volatile 变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic vari ables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。 我认为这是区分 C 程序员和嵌入式 系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS 等等 打交道,所用这些都要求 volatile 变量。不懂得 volatile 内容将会带来灾难。 我将稍微深究一下 volatile 的重要性。 1). 一个参数既可以是 const 还可以是 volatile 吗?解释为什么。 2). 一个指针可以是 volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; } 下面是答案: 1). 是的。一个例子是只读的状态寄存器。它是 volatile 因为它可能被意想 不到地改变。它是 const 因为程序不应该试图去修改它。 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指 向一个 buffer 的指针时。 3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr 指向值的 平方,但是,由于*ptr 指向一个 volatile 型参数,编译器将产生类似下面的代 码: int square(volatile int *ptr) {

volatile修饰方法

volatile修饰方法

volatile修饰方法(原创版3篇)目录(篇1)一、volatile 修饰方法的概念二、volatile 修饰方法的作用三、volatile 修饰方法的实例四、volatile 修饰方法的注意事项正文(篇1)一、volatile 修饰方法的概念在 Java 编程语言中,volatile 修饰方法是一种用于声明方法的修饰符,它可以确保方法的执行过程在多线程环境下具有可见性和有序性。

volatile 修饰方法与 volatile 修饰变量类似,都是为了解决多线程编程中的同步问题。

二、volatile 修饰方法的作用volatile 修饰方法主要具有以下作用:1.可见性:当一个线程修改了 volatile 修饰方法的返回值,其他线程可以立即看到这个修改。

这保证了在多线程环境下,volatile 修饰方法的返回值不会出现脏数据。

2.有序性:volatile 修饰方法可以确保在多线程环境下,方法的执行顺序与程序的顺序一致。

这对于避免死锁和数据竞争等问题具有重要意义。

三、volatile 修饰方法的实例下面是一个使用 volatile 修饰方法的实例:```javapublic class VolatileExample {public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(counter::increment); Thread t2 = new Thread(counter::decrement); t1.start();t2.start();System.out.println(counter.getCount());}}class Counter {private volatile int count;public int getCount() {return count;}public void increment() {count++;}public void decrement() {count--;}}```在这个例子中,Counter 类的 count 变量被 volatile 修饰,确保了在多线程环境下,count 变量的可见性和有序性。

volatile关键字作用,原理

volatile关键字作用,原理

volatile是一个在多线程编程中用来声明变量的关键字。

它的作用是告诉编译器和运行时系统,这个变量可能会被多个线程同时访问,因此不应该进行一些优化,例如缓存该变量的值。

作用:
1.禁止指令重排序:volatile保证被修饰的变量的读写操作不会被重排序。


多线程环境中,指令重排序可能导致程序出现意外的行为,而使用volatile
可以防止这种情况。

2.可见性:volatile保证一个线程对该变量的修改对其他线程是可见的。

也就
是说,当一个线程修改了volatile变量的值,这个新值会立即对其他线程可
见。

原理:
1.禁止缓存:使用volatile关键字告诉编译器,不要将这个变量缓存在寄存器
或者对其他线程不可见的地方。

每次访问volatile变量时,都会从内存中读
取最新的值,而不是使用缓存中的值。

2.内存屏障(Memory Barrier):在编译器生成的汇编代码中,volatile变量
的读写操作会被编译器插入内存屏障指令,确保变量的读写操作按照顺序执行。

内存屏障可以防止指令重排序,同时保证多核处理器中的可见性。

需要注意的是,虽然volatile可以保证可见性和防止指令重排序,但它并不能保证原子性。

如果一个变量的操作是由多个步骤组成的,volatile不能保证这些步骤的原子性,因此在需要原子性的操作时,还需要使用其他机制,例如synchronized关键字或者java.util.concurrent包中的原子类。

volative的作用

volative的作用

volatile作用volatile的作用一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile 变量的几个例子:1). 并行设备的硬件寄存器(如:状态寄存器)2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)3). 多线程应用中被几个任务共享的变量回答不出这个问题的人是不会被雇佣的。

我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。

嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。

不懂得volatile内容将会带来灾难。

假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

1). 一个参数既可以是const还可以是volatile吗?解释为什么。

2). 一个指针可以是volatile 吗?解释为什么。

3). 下面的函数有什么错误:int square(volatile int *ptr){return *ptr * *ptr;}下面是答案:1). 是的。

一个例子是只读的状态寄存器。

它是volatile因为它可能被意想不到地改变。

它是const因为程序不应该试图去修改它。

2). 是的。

尽管这并不很常见。

一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

3). 这段代码的有个恶作剧。

这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:int square(volatile int *ptr){int a,b;a = *ptr;b = *ptr;return a * b;}由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。

c语言中volatile的用法

c语言中volatile的用法

c语言中volatile的用法引言在C语言中,volatile是一个非常重要的关键字,它告诉编译器某个变量可能会被意外的改变,从而防止编译器对这些变量进行优化。

本文将介绍volatile的定义、用法以及其在多线程、嵌入式开发中的应用。

一、定义与作用volatile关键字是C语言中用来声明变量的一种类型修饰符,它用于告知编译器该变量可能被在程序执行中意外地改变,编译器在编译过程中会尽量避免对volatile 变量的优化。

volatile常见的作用有以下几个方面: 1. 防止编译器优化:编译器在进行优化时,会根据程序的逻辑简化一些操作,如果一个变量的值不会被程序以外的因素改变,编译器可能会进行一些优化,将变量的读取操作删除或进行替换。

而使用volatile 修饰变量,可以告诉编译器不要对该变量进行优化,保证变量的读取和写入操作不被删除或替换。

2.处理硬件映射:在嵌入式开发中,通常会有一些变量与硬件设备进行映射,这些变量的值可能会被硬件设备修改。

如果不使用volatile修饰这些变量,在编译器优化的过程中可能会导致未预料的结果,使用volatile修饰这些变量可以确保程序正确地与硬件设备进行通信。

3.多线程同步:在多线程编程中,不同线程可能同时访问同一个变量,如果不使用volatile修饰该变量,编译器对该变量的优化可能导致线程读取到脏数据。

通过使用volatile修饰变量,可以确保在多线程环境下变量的可见性和一致性。

二、volatile与多线程并发编程中最常见的一个问题就是可见性问题,即一个线程对共享变量的修改对另一个线程是否可见。

而volatile关键字可以用来确保变量在多线程环境下的可见性。

以下是volatile与多线程相关的一些要点:1. 可见性使用volatile修饰的变量在多线程环境下保证了其可见性。

如果一个线程对一个volatile变量进行了修改,那么其他线程在读取该变量时可以立即看到最新的值,而不会使用缓存中的旧值。

volatile的用法

volatile的用法

volatile的用法Volatile关键字是C和C++中的一个关键字,它指定变量在程序执行期间可能会被修改。

被volatile修饰的变量能够在多线程和多进程的环境中确保线程安全。

在防止出现不期望的行为中,Volatile变量在嵌入式系统和并发系统中扮演着重要角色。

下面让我们深入探讨Volatile 的使用方法。

定义:Volatile关键字应用于一个变量的定义中。

例如:volatile int val = 10;这样做可以告诉编译器,变量val的值可能在其他线程或其他进程中被修改,确保在多线程操作时执行线程从内存中获取数据而不是从缓存区中获取数据。

访问:Volatile变量比普通变量更慢,因为每次访问它时,都需要从内存中获取数据,而不是读取CPU缓存中的值。

但是,在多线程和多进程的情况下,Volatile访问是必需的。

使用场景:需要在一个变量的多个线程或多个进程中共享数据时,就需要使用Volatile关键字。

例如,在社交媒体应用场景下,一个计数器被多个线程或进程共享,如果不使用Volatile关键字,会使其中一个线程或进程更改该计数器的值,而另外的线程或进程将不知道这个值的变化,导致整个统计计数的功能出现错误。

使用Volatile关键字,能够确保每个线程或进程均可以看到该计数器的正确值。

小心使用:在多线程应用程序中,Volatile虽然可以确保数据在多个线程中共享,但是使用它还是要小心。

如果在程序执行期间需要一个数据是不会被改变的,则不应该使用Volatile。

在多个线程之间共享数据时,使用锁机制或者原子操作也是非常必要的。

总结:根据需要,使用Volatile可以保证程序的正确性。

如果需要确保多个线程或进程共享变量的正确性或不同进程中的变量的正确性,那么请使用它。

记住,不要过度使用Volatile变量,因为它会使程序变慢。

小心关键字,确保在需要并发时使用它。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

转载来自hbtian的笔记讲讲volatile的作用一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:1). 并行设备的硬件寄存器(如:状态寄存器)2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)3). 多线程应用中被几个任务共享的变量回答不出这个问题的人是不会被雇佣的。

我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。

嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile 变量。

不懂得volatile内容将会带来灾难。

假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

1). 一个参数既可以是const还可以是volatile吗?解释为什么。

2). 一个指针可以是volatile 吗?解释为什么。

3). 下面的函数有什么错误:int square(volatile int *ptr){return *ptr * *ptr;}下面是答案:1). 是的。

一个例子是只读的状态寄存器。

它是volatile因为它可能被意想不到地改变。

它是const因为程序不应该试图去修改它。

2). 是的。

尽管这并不很常见。

一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

3). 这段代码的有个恶作剧。

这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:int square(volatile int *ptr){int a,b;a = *ptr;b = *ptr;return a * b;}由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。

结果,这段代码可能返不是你所期望的平方值!正确的代码如下:long square(volatile int *ptr){int a;a = *ptr;return a * a;}讲讲我的理解:(欢迎打板子...~~!)关键在于两个地方:1. 编译器的优化 (请高手帮我看看下面的理解)在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致举一个不太准确的例子:发薪资时,会计每次都把员工叫来登记他们的银行卡号;一次会计为了省事,没有即时登记,用了以前登记的银行卡号;刚好一个员工的银行卡丢了,已挂失该银行卡号;从而造成该员工领不到工资员工--原始变量地址银行卡号--原始变量在寄存器的备份2. 在什么情况下会出现(如1楼所说)1). 并行设备的硬件寄存器(如:状态寄存器)2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)3). 多线程应用中被几个任务共享的变量补充:volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人;“易变”是因为外在因素引起的,象多线程,中断等,并不是因为用volatile修饰了的变量就是“易变”了,假如没有外因,即使用volatile定义,它也不会变化;而用volatile定义之后,其实这个变量就不会因外因而变化了,可以放心使用了;大家看看前面那种解释(易变的)是不是在误导人------------简明示例如下:------------------volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。

遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

使用该关键字的例子如下:int volatile nVint;>>>>当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。

而且读取的数据立刻被保存。

例如:volatile int i=10;int a = i;...//其他代码,并未明确告诉编译器,对i进行过操作int b = i;>>>>volatile 指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。

而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。

而不是重新从i里面读。

这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

>>>>注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。

下面通过插入汇编代码,测试有无volatile关键字,对程序最终代码的影响:>>>>首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:>>#i nclude <stdio.h>void main(){int i=10;int a = i;printf("i= %d",a);//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道__asm {mov dword ptr [ebp-4], 20h}int b = i;printf("i= %d",b);}然后,在调试版本模式运行程序,输出结果如下:i = 10i = 32然后,在release版本模式运行程序,输出结果如下:i = 10i = 10输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。

下面,我们把i的声明加上volatile关键字,看看有什么变化:#i nclude <stdio.h>void main(){volatile int i=10;int a = i;printf("i= %d",a);__asm {mov dword ptr [ebp-4], 20h}int b = i;printf("i= %d",b);}分别在调试版本和release版本运行程序,输出都是:i = 10i = 32这说明这个关键字发挥了它的作用!------------------------------------volatile对应的变量可能在你的程序本身不知道的情况下发生改变比如多线程的程序,共同访问的内存当中,多个程序都可以操纵这个变量你自己的程序,是无法判定合适这个变量会发生变化还比如,他和一个外部设备的某个状态对应,当外部设备发生操作的时候,通过驱动程序和中断事件,系统改变了这个变量的数值,而你的程序并不知道。

对于volatile类型的变量,系统每次用到他的时候都是直接从对应的内存当中提取,而不会利用cache当中的原有数值,以适应它的未知何时会发生的变化,系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。

--------------------------------------------------------------------------------典型的例子for ( int i=0; i<100000; i++);这个语句用来测试空循环的速度的但是编译器肯定要把它优化掉,根本就不执行如果你写成for ( volatile int i=0; i<100000; i++);它就会执行了volatile的本意是“易变的”由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。

比如:static int i=0;int main(void){...while (1){if (i) dosomething();}/* Interrupt service routine. */void ISR_2(void){i=1;}程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致dosomething永远也不会被调用。

如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。

此例中i也应该如此说明。

一般说来,volatile用在如下的几个地方:1、中断服务程序中修改的供其它程序检测的变量需要加volatile;2、多任务环境下各任务间共享的标志应该加volatile;3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。

相关文档
最新文档