volatile用法
volatile测试用例
volatile测试用例一、介绍在编程语言中,volatile关键字是用来修饰变量的,它的作用是告诉编译器或虚拟机,该变量可能在任何时刻被其他线程修改,因此需要从主内存中读取最新的值。
本文将通过一些示例来说明volatile关键字的作用和使用方法。
二、volatile关键字的作用1. 可见性:在多线程环境下,volatile保证了变量的可见性。
当一个线程修改了volatile修饰的变量的值,其他线程能立即看到最新的值,而不是使用缓存中的旧值。
2. 有序性:在多线程环境下,volatile保证了变量的有序性。
编译器或虚拟机会对volatile变量的访问进行特殊处理,确保变量的读写操作按照代码的顺序执行。
3. 禁止指令重排序:在多线程环境下,volatile关键字禁止指令重排序。
编译器或虚拟机会根据volatile的语义对指令进行排序,保证在执行volatile变量的读写操作时,不会受到指令重排序的影响。
三、volatile关键字的使用方法1. 声明变量时使用volatile关键字:在声明变量时,可以使用volatile关键字修饰变量,例如:volatile int count = 0;。
这样一来,该变量就具备了可见性、有序性和禁止指令重排序的特性。
2. 使用volatile关键字修饰共享变量:当多个线程同时访问一个共享变量时,可以使用volatile关键字修饰该变量,以确保线程之间的可见性和有序性。
3. 注意volatile不能保证原子性:虽然volatile关键字可以保证变量的可见性和有序性,但不能保证变量的原子性。
如果需要保证变量的原子性,可以使用synchronized关键字或Lock接口来实现。
下面我们通过一个简单的示例来测试volatile关键字的作用。
```javapublic class VolatileTest {private volatile boolean flag = false;public static void main(String[] args) {VolatileTest test = new VolatileTest();new Thread(() -> {while (!test.flag) {// do something}System.out.println("Flag is true");}).start();new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}test.flag = true;}).start();}}```在上述代码中,我们声明了一个volatile修饰的boolean类型的变量flag,并创建了两个线程。
volatility的形容词
volatility的形容词Volatility的形容词是"volatile",意思是易变的、不稳定的。
1. The stock market is known for being volatile, with prices fluctuating wildly.股市因价格波动剧烈而出名。
2. The weather in this region is extremely volatile, with sudden changes from sunshine to thunderstorms.该地区的天气极其多变,时晴时雷雨。
3. Their relationship is quite volatile, with constant arguments and reconciliations.他们的关系非常不稳定,经常争吵和和好。
4. The political situation in the country is volatile, with protests and demonstrations occurring frequently.该国的政治局势动荡不安,频繁发生抗议和示威活动。
5. The volatile market conditions make it difficult for investors to predict returns on their investments.不稳定的市场条件使得投资者难以预测投资回报。
6. The price of gasoline is highly volatile, with frequent increases and decreases.汽油价格波动较大,涨跌频繁。
7. The teenager's volatile behavior is causing concern among his parents and teachers.这位十几岁的青少年的行为反复无常,引起了他的家长和老师的担忧。
volatile用法及原理
volatile用法及原理
"volatile"是一个关键字,用于修饰变量。
它可以告诉编译器,在使用这个变量的时候不要
进行优化,每次都从内存中读取最新的值,而不是使用寄存器中保存的值。
"volatile"的主要使用场景有两种:
1. 多线程并发访问共享变量:当多个线程同时访问一个共享变量时,为了保证数据的可见性和一致性,可以使用"volatile"关键字修饰共享变量,确保每次读取变量时都能获取到最新的值,
而不是使用缓存中的旧值。
2. 硬件设备的内存映射:有些变量是映射到硬件设备的内存地址,每次读取或写入这些变量时都需要与硬件设备进行交互。
使用"volatile"关键字修饰这些变量,可以告诉编译器不要对这些
变量进行优化,并且保证每次读取或写入都直接与硬件设备进行交互。
原理上,"volatile"关键字的作用是通过一系列的指令和内存屏障来保证变量的可见性和有序性:
1. 可见性:当一个线程对一个volatile变量进行写操作时,会立即刷新到主内存中,而读操作
会直接从主内存中读取最新的值,保证可见性。
2. 有序性:在volatile变量的前后插入内存屏障指令,防止指令重排序的优化。
这样可以确保volatile变量的读写操作在其他指令之前执行或之后执行,保证操作顺序的有序性。
需要注意的是,虽然"volatile"关键字可以保证可见性和有序性,但它并不能保证原子性。
如果
要保证原子性,需要使用其他的同步手段,比如使用synchronized关键字或者使用锁机制。
java volatile 用法
一、java中volatile关键字的作用在Java中,volatile是一种轻量级的同步机制,主要用于多线程之间的变量可见性和防止指令重排序。
二、volatile关键字的使用场景1. 适用于多线程对共享变量的操作在多线程环境下,如果一个变量被多个线程操作并且这些线程之间没有同步的机制,那么很有可能会出现数据不一致的情况。
此时可以使用volatile关键字来保证变量的可见性,即当一个线程修改了这个变量的值,其他线程可以立即看到最新的值。
2. 适用于简单的标志位控制当一个变量在多个线程中被频繁修改,但是对这个变量的修改并不依赖于当前值时,可以使用volatile关键字来提高性能。
一个标志位用于控制线程的启停,这种情况下可以使用volatile来保证线程之间的及时通知。
三、volatile关键字的使用注意事项1. 不保证原子性Volatile关键字只能保证变量的可见性和禁止指令重排序,但不能保证原子性。
如果一个操作是原子性的,那么使用volatile是不够的,需要配合使用synchronized或者Lock来保证原子性操作。
2. 可能存在有序性问题在JDK1.5之前,volatile关键字可能存在指令重排序的问题,导致代码执行的顺序和预期不符。
但在JDK1.5及以后,Java语言的内存模型对volatile的语义做出了修订,可以保证变量的有序性。
3. 要注意内存可见性对于volatile修饰的变量,当一个线程修改了这个变量的值,其他线程会立即看到最新的值。
这种特性使得volatile变量适合作为控制变量,但在一些复杂的操作场景下仍需谨慎使用。
四、volatile关键字的使用示例```javapublic class VolatileExample {private volatile boolean flag = false;public void toggleFlag() {flag = !flag;}public boolean isFlag() {return flag;}}```以上代码展示了一个简单的示例,其中flag变量被volatile修饰,保证了其可见性。
volatile的用法
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 C++中volatile的用法
C/C++中volatile的用法代码编译环境:Windows7 32bits+VS2012。
volatile是“易变的”、“不稳定”的意思。
volatile是C/C++的一个较为少用的关键字,它用来解决变量在“共享”环境下容易出现的读取错误的问题。
1.volatile的作用定义为volatile的变量是说这变量可能会被意想不到地改变,编译器在优化时,用到这个变量每次都从重新从RAM读取这个变量的值,而不是使用保存在寄存器里的备份。
在单任务的环境中,一个函数体内部,如果在两次读取变量的值之间的语句没有对变量的值进行修改,那么编译器就会设法对可执行代码进行优化。
由于访问寄存器的速度要快过RAM(从RAM中读取变量的值到寄存器),以后只要变量的值没有改变,就一直从寄存器中读取变量的值,而不对RAM进行访问。
而在多任务环境中,虽然在一个函数体内部,在两次读取变量之间没有对变量的值进行修改,但是该变量仍然有可能被其他的程序(如中断程序、另外的线程等)所修改。
如果这厮还是从寄存器而不是从RAM中读取变量的值,就会出现被修改了的比阿郎的之不能及时的反应的问题。
如下程序对这一现象进行了模拟:#include<iostream>using namespace std;int main(int argc,char* argv[]){int i=10;int a=i;cout<<a<<endl;_asm{mov dword ptr [ebp-4],80}int b=i;cout<<b<<endl;getchar();}程序在VS2012环境下生成Release版本,输出结果是:1010阅读以上程序,注意一下几个要点:(1)以上代码必须在release模式下考查,因为只有Release模式下才会对程序代码进行优化,而这种优化在变量共享的环境下容易引发问题。
(2)在语句b=i;之前,已经通过内联汇编代码修改了i的值,但是i的变化却没有反映到b中,如果i是一个被多个任务共享的变量,这种优化带来的错误很可能是致命的。
c++中的volatile用法
在C++编程中,volatile是一个非常关键的关键字,它用于告诉编译器不要对定义为volatile的变量进行优化,因为这些变量的值可能会在程序的控制流之外被改变。
在本文中,我将以深度和广度的方式来探讨C++中volatile的用法,以便你能更深入地理解这一重要概念。
1. 什么是volatile?在C++中,volatile是一个关键字,它可以应用于指定的变量,告诉编译器不要对该变量进行优化。
通常情况下,编译器会对变量进行优化以提高程序的性能,但对于被声明为volatile的变量,编译器会禁止这种优化。
这是因为volatile变量的值可能会在程序控制流之外被改变,比如硬件寄存器,中断服务子程序等。
2. volatile的使用场景在实际编程中,volatile主要用于以下几个方面:2.1. 多线程编程:在多线程编程中,volatile可用于标记多线程共享的变量,以确保每个线程都能看到最新的值。
2.2. 与硬件相关的编程:在与硬件相关的编程中,比如嵌入式系统开发,volatile可用于标记与硬件相关的寄存器变量,以确保其值不会被编译器优化掉。
2.3. 信号处理:在信号处理的场景中,volatile可用于标记被信号处理函数访问的变量,以确保编译器不会对其进行优化。
3. volatile的注意事项在使用volatile时,需要注意以下几点:3.1. 不要滥用volatile:虽然volatile可以防止编译器对变量进行优化,但不应滥用它。
只有在确实需要volatile时才使用它。
3.2. 谨慎使用volatile和多线程:在多线程编程中,volatile能确保每个线程都能看到最新的值,但仍需谨慎使用,并结合其他同步机制(比如互斥量、原子操作等)来确保线程安全。
4. 我的观点和理解在我看来,volatile是一个非常重要的关键字,在特定的场景下能起到关键作用。
在多线程编程和与硬件相关的编程中,正确地使用volatile 可以确保程序的正确性和可靠性。
volatile作用和用法
volatile作用和用法volatile关键字是C和C++语言中经常用到的关键字之一,它的作用是告诉编译器在处理变量时应该尽可能地遵循在编译过程中该变量可能发生改变的情况。
volatile关键字的主要作用在于告诉编译器该变量并不是固定不变的,因此在处理该变量时需要特别的小心谨慎。
当我们定义一个变量为volatile类型时,我们告诉编译器这个变量可能随时会被变更,因此不必将该变量缓存至寄存器中,对该变量的读写操作必须直接操作其在内存中的值。
通常而言,一般的程序是可以将变量缓存至寄存器中,以便更快地访问该变量。
但是,如果一个变量是volatile类型的,编译器必须保证每次都从内存中读取该变量的值,因为该变量有可能被其他线程、中断程序或硬件修改。
在外设操作中,volatile的使用是很普遍的。
因为外设数据寄存器在程序每次读取时都可能发生变化。
如果不加volatile关键字,编译器会将寄存器的值缓存在寄存器中,从而导致程序无法得到最新的外设数据。
volatile的使用也是很通用的,比如多线程编程、编写操作系统时驱动程序的编写等等。
volatile关键字同样也适用于指针类型。
当我们定义指向某个数值的指针时,编译器同样可能会将该值缓存至寄存器中,如果该变量是volatile类型,那么就会由于缓存导致使用陈旧的数值。
同时,如果我们在定义一个volatile指针时,也需要特别注意该指针的使用。
因为指针变量也有可能被其它线程修改或误操作,所以需要在处理volatile指针时非常小心谨慎。
总之,volatile关键字在处理多线程、中断程序或硬件时,是一个非常重要的保障,能够保证程序对变量的读写操作符合程序设计的预期,是编写可靠、高效程序的重要技巧之一。
volatile使用场景
volatile使用场景Volatile使用场景Volatile是Java中的一个关键字,用于修饰变量,表示该变量是易变的,可能会被多个线程同时访问和修改。
在多线程编程中,Volatile的使用场景非常广泛,下面将按照不同的类别来介绍。
一、状态标记在多线程编程中,经常需要使用状态标记来控制线程的执行流程。
例如,一个线程需要等待另一个线程完成某个操作后才能继续执行,这时可以使用一个状态标记来表示另一个线程是否已经完成了操作。
这个状态标记可以使用Volatile来修饰,以保证多个线程之间的可见性。
二、双重检查锁定双重检查锁定是一种常见的单例模式实现方式,它可以保证在多线程环境下只有一个实例被创建。
在双重检查锁定中,需要使用Volatile来修饰单例对象,以保证多个线程之间的可见性。
三、计数器在多线程编程中,经常需要使用计数器来统计某个操作的执行次数。
例如,一个线程需要等待多个线程都完成某个操作后才能继续执行,这时可以使用一个计数器来统计已经完成操作的线程数量。
这个计数器可以使用Volatile来修饰,以保证多个线程之间的可见性。
四、轻量级同步在多线程编程中,经常需要使用轻量级同步来保证线程安全。
例如,一个线程需要对某个变量进行读写操作,但是这个变量的读写操作并不需要使用重量级的锁,这时可以使用Volatile来修饰这个变量,以保证多个线程之间的可见性。
总之,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与sychronized使用场景及原理
volatile与sychronized使用场景及原理
volatile和synchronized都是Java中用于实现多线程并发安全的关键字,但是它们的使用场景和原理有所不同。
1. volatile的使用场景:
- 在一个线程修改了一个volatile变量的值之后,其他线程能够立即看到该变量的最新值。
- 当一个变量被多个线程共享,并且其中一个线程修改了这个变量的值,需要将修改后的值立即刷新到主内存中,以便其他线程能够立即看到最新值。
- 适用于对变量的写操作不依赖于当前值,或者只有一个线程修改变量的值,其他线程只读取变量的值。
2. volatile的原理:
- volatile修饰的变量会被存放在主内存中,而不是线程的工作内存中。
- 每次线程读取volatile变量的值时,都会直接从主内存中读取最新值,而不是使用线程工作内存中的副本。
- 每次线程修改volatile变量的值时,会立即将修改后的值刷新到主内存,以便其他线程能够立即看到最新值。
3. synchronized的使用场景:
- 当多个线程访问共享资源时,需要防止并发修改引起的数据不一致。
- 当一个线程需要锁定一个对象以执行同步方法或同步代码块时。
4. synchronized的原理:
- synchronized保证了同一时刻只有一个线程可以执行被synchronized修饰的方法或代码块。
- 内置锁(或监视器锁)是通过对象头中的标志位来实现的。
- 当一个线程尝试获取对象的锁时,如果锁没有被其他线程
持有,那么该线程就会获取到锁,执行同步方法或代码块;否则,该线程就会进入锁定状态,直到持有锁的线程释放锁。
c语言中volatile的用法
c语言中volatilevolatile:Tending to vary often or widely, as in price:易波动的,不稳定的:易于经常或大幅度变化的,如价格:the ups and downs of volatile stocks.易波动的股票沉浮Inconstant; fickle:易变的,多变的:a flirt's volatile affections.浪荡子多变的爱情Lighthearted; flighty:活泼的,轻快的:in a volatile mood.轻快的心情Ephemeral; fleeting.短暂的,易逝的Tending to violence; explosive:易爆发的;爆炸性的:a volatile situation with troops and rioters eager for a confrontation. 军队和暴民间爆炸性对立的局势volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。
)。
例如:volatile int i=10;int j = i;...int k = i;volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。
而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。
而不是重新从i里面读。
这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile 可以保证对特殊地址的稳定访问,不会出错。
总结:如果一个变量可能会被除程序本身以外的其他因素改变,就必须声明为volatile例如在编写驱动程序时,定义设备结构(DEV struct)always in this mode: typdef volatile struct{}np_uart,np_time ,etc因为设备内部的寄存变量通常是随时变动的,不受内部主程序的控制,so 声明为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变量,因为它会使程序变慢。
小心关键字,确保在需要并发时使用它。
c++ const volatile用法
c++ const volatile用法在C++中,const和volatile都是限定符,用于修改变量的性质。
它们可以单独使用,也可以一起使用。
1. const关键字:- const用于修饰变量,表示该变量的值不可被修改。
声明为const的变量在程序执行过程中不能被修改。
当尝试修改const变量的值时,会导致编译错误。
- const还可以用于修饰函数参数和函数返回类型,表示函数不会修改该参数的值,并且返回的值也是const。
2. volatile关键字:- volatile用于修饰变量,表示该变量的值可以在程序执行过程中被意外地修改。
通常,编译器会对变量进行优化,将变量的值缓存到寄存器中,但是使用volatile关键字修饰的变量,编译器会强制从内存中读取变量的最新值,以便确保变量的可见性。
- volatile通常用于多线程编程或与硬件相关的场景,用来处理共享变量的并发访问问题。
3. const volatile:- const volatile用于同时修饰变量,表示该变量既不可修改也可能被意外地修改。
这在一些特殊情况下使用,比如用于访问硬件寄存器,该寄存器的值可能会不可预测地被修改,并且应用程序无法修改该值。
例如:```cppconst int MAX_VALUE = 100; // 声明常量,不可修改volatile int sensorValue = 0; // 声明一个可能被其他线程修改的变量void foo(const volatile int* ptr) {// 函数参数为const volatile指针,表示函数不会修改指针指向的内容,并且内容可能会在执行过程中被修改int value = *ptr; // 从内存中读取指针指向的值,而不是从寄存器中读取// ...}const volatile int* bar() {// 函数返回类型为const volatile指针,表示返回的指针指向的内容可能会在执行过程中被修改volatile int* ptr = &sensorValue;return ptr;}```。
C语言中const,volatile,restrict的用法总结
C语⾔中const,volatile,restrict的⽤法总结变量声明中带有关键词const,,这是显⽽易见的⼀点。
指针使⽤const则要稍微复杂点,因为不得不把让指针本⾝成为const 和指针指向的值成为const区别开来、下⾯的声明表⽰pf指向的值必须是不变的constfloat *pf;⽽pf则是可变的,它可以指向另外⼀个const或⾮const值;相反,下⾯的声明说明pf是不能改变的,⽽pf所指向的值则是可以改变的:float* const pf;最后,当然可以有既不能改变指针的值也不能改变指针指向的值的值的声明⽅式:constfloat * const pf;需要注意的是,还有第三种放置const关键字的⽅法:float const * pf; //等价于constfloat * pf;总结就是:⼀个位于*左边任意位置的const使得数据成为常量,⽽⼀个位于*右边的const使得指针本⾝成为const还要注意的⼀点是关于const在全局数据中的使⽤:使⽤全局变量被认为是⼀个冒险的⽅法,它使得数据在程序的任何部分都可以被错误地修改,如果数据是const,那么这种担⼼就是多余的了不是嘛?因此对全局数据使⽤const是合理的。
然⽽,在⽂件之间共享const数据要格外⼩⼼,有两个策略可以使⽤。
⼀个是遵循外部变量的惯⽤规则,在⼀个⽂件进⾏定义声明,在其他⽂件进⾏引⽤声明(使⽤关键字extern)。
/*file1.c------定义⼀些全局常量*/const double PI = 3.14159;/*file2.c-----是⽤在其他⽂件中定义的全局变量*/extern const dounle PI;另外⼀个⽅法是把全局变量放在⼀个include⽂件⾥,这时候需要格外注意的是必须使⽤静态外部存储类/*constant.h----定义⼀些全局常量*/static const double PI = 3.14159;/*file1.c-----使⽤其他⽂件定义的全局变量*/#include”constant.h”。
volatile 用法
嵌入式编程中经常用到 volatile这个关键字,在网上查了下他的用法找到了下面这3篇文章比较好的:一:告诉compiler不能做任何优化比如要往某一地址送两指令:int *ip =...; //设备地址*ip = 1; //第一个指令*ip = 2; //第二个指令以上程序compiler可能做优化而成:int *ip = ...;*ip = 2;结果第一个指令丢失。
如果用volatile, compiler就不允许做任何的优化,从而保证程序的原意:volatile int *ip = ...;*ip = 1;*ip = 2;即使你要compiler做优化,它也不会把两次付值语句间化为一。
它只能做其它的优化。
这对device driver程序员很有用。
二:表示用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能把他放在cache或寄存器中重复使用。
如 volatile char a;a=0;while(!a){//do some things;}doother();如果没有 volatile doother()不会被执行还找到一篇比较详细的比较CONST和Volatile的文章8.4. Const and volatileThese are new in Standard C, although the idea of const has been borrowed from C++. Let us get one thing straight: the concepts of const and volatile are completely independent. A common misconception is to imagine that somehow const is the opposite of volatile and vice versa. They are unrelated and you should remember the fact.Since const declarations are the simpler, we'll look at them first, but only after we have seen where both of these type qualifiers may be used. The complete list of relevant keywords ischar long float volatileshort signed double voidint unsigned constIn that list, const and volatile are type qualifiers, the rest are type specifiers. Various combinations of type specifiers are permitted:char, signed char, unsigned charint, signed int, unsigned intshort int, signed short int, unsigned short intlong int, signed long int, unsigned long intfloatdoublelong doubleA few points should be noted. All declarations to do with an int will be signed anyway, so signed is redundant in that context. If any other type specifier or qualifier is present, then the int part may be dropped, as that is the default.The keywords const and volatile can be applied to any declaration, including those of structures, unions, enumerated types or typedef names. Applying them to a declaration is called qualifying the declaration—that's why const and volatile are called type qualifiers, rather than type specifiers. Here are a few representative examples:volatile i;volatile int j;const long q;const volatile unsigned long int rt_clk;struct{const long int li;signed char sc;}volatile vs;Don't be put off; some of them are deliberately complicated: what they mean will be explained later. Remember that they could also be further complicated by introducing storage class specifications as well! In fact, the truly spectacular extern const volatile unsigned long int rt_clk;is a strong possibility in some real-time operating system kernels.8.4.1. ConstLet's look at what is meant when const is used. It's really quite simple: const means that something is not modifiable, so a data object that is declared with const as a part of its type specification must not be assigned to in any way during the run of a program. It is very likely that the definition of the object willcontain an initializer (otherwise, since you can't assign to it, how would it ever get a value?), but this is not always the case. For example, if you were accessing a hardware port at a fixed memory address and promised only to read from it, then it would be declared to be const but not initialized.Taking the address of a data object of a type which isn't const and putting it into a pointer to the const-qualified version of the same type is both safe and explicitly permitted; you will be able to use the pointer to inspect the object, but not modify it. Putting the address of a const type into a pointer to the unqualified type is much more dangerous and consequently prohibited (although you can get around this by using a cast). Here is an example:#include#includemain(){int i;const int ci = 123;/* declare a pointer to a const.. */const int *cpi;/* ordinary pointer to a non-const */int *ncpi;cpi = &ci;ncpi = &i;/** this is allowed*/cpi = ncpi;/** this needs a cast* because it is usually a big mistake,* see what it permits below.*/ncpi = (int *)cpi;/** now to get undefined behaviour...* modify a const through a pointer*/*ncpi = 0;exit(EXIT_SUCCESS);}Example 8.3As the example shows, it is possible to take the address of a constant object, generate a pointer to a non-constant, then use the new pointer. This isan error in your program and results in undefined behaviour.The main intention of introducing const objects was to allow them to be put into read-only store, and to permit compilers to do extra consistency checking in a program. Unless you defeat the intent by doing naughty things with pointers, a compiler is able to check that const objects are not modified explicitly by the user.An interesting extra feature pops up now. What does this mean?char c;char *const cp = &c;It's simple really; cp is a pointer to a char, which is exactly what it would be if the const weren't there. The const means that cp is not to be modified, although whatever it points to can be—the pointer is constant, not the thing that it points to. The other way round isconst char *cp;which means that now cp is an ordinary, modifiable pointer, but the thing that it points to must not be modified. So, depending on what you choose to do, both the pointer and the thing it points to may be modifiable or not; just choose the appropriate declaration.8.4.2. VolatileAfter const, we treat volatile. The reason for having this type qualifier is mainly to do with the problems that are encountered in real-time or embedded systems programming using C. Imagine that you are writing code that controls a hardware device by placing appropriate values in hardware registers at known absolute addresses.Let's imagine that the device has two registers, each 16 bits long, at ascending memory addresses; the first one is the control and status register (csr) and the second is a data port. The traditional way of accessing such a device is like this: /* Standard C example but without const or volatile *//** Declare the device registers* Whether to use int or short* is implementation dependent*/struct devregs{unsigned short csr; /* control & status */unsigned short data; /* data port */};/* bit patterns in the csr */#define ERROR 0x1#define READY 0x2#define RESET 0x4/* absolute address of the device */#define DEVADDR ((struct devregs *)0xffff0004)/* number of such devices in system */#define NDEVS 4/** Busy-wait function to read a byte from device n.* check range of device number.* Wait until READY or ERROR* if no error, read byte, return it* otherwise reset error, return 0xffff*/unsigned int read_dev(unsigned devno){struct devregs *dvp = DEVADDR + devno;if(devno >= NDEVS)return(0xffff);while((dvp->csr & (READY | ERROR)) == 0); /* NULL - wait till done */if(dvp->csr & ERROR){dvp->csr = RESET;return(0xffff);}return((dvp->data) & 0xff);}Example 8.4The technique of using a structure declaration to describe the device register layout and names is very common practice. Notice that there aren't actually any objects of that type defined, so the declaration simply indicates the structure without using up any store.To access the device registers, an appropriately cast constant is used as if it were pointing to such a structure, but of course it points to memory addresses instead.However, a major problem with previous C compilers would be in the while loop which tests the status register and waits for the ERROR or READY bit to come on. Any self-respecting optimizing compiler would notice that the loop tests the same memory address over and over again. It would almost certainly arrange toreference memory once only, and copy the value into a hardware register, thus speeding up the loop. This is, of course, exactly what we don't want; this is one of the few places where we must look at the place where the pointer points, every time around the loop.Because of this problem, most C compilers have been unable to make that sort of optimization in the past. To remove the problem (and other similar ones to do with when to write to where a pointer points), the keyword volatile was introduced. It tells the compiler that the object is subject to sudden change for reasons which cannot be predicted from a study of the program itself, and forces every reference to such an object to be a genuine reference.Here is how you would rewrite the example, making use of const and volatile to get what you want./** Declare the device registers* Whether to use int or short* is implementation dependent*/struct devregs{unsigned short volatile csr;unsigned short const volatile data;};/* bit patterns in the csr */#define ERROR 0x1#define READY 0x2#define RESET 0x4/* absolute address of the device */#define DEVADDR ((struct devregs *)0xffff0004)/* number of such devices in system */#define NDEVS 4/** Busy-wait function to read a byte from device n.* check range of device number.* Wait until READY or ERROR* if no error, read byte, return it* otherwise reset error, return 0xffff*/unsigned int read_dev(unsigned devno){struct devregs * const dvp = DEVADDR + devno;if(devno >= NDEVS)return(0xffff);while((dvp->csr & (READY | ERROR)) == 0); /* NULL - wait till done */if(dvp->csr & ERROR){dvp->csr = RESET;return(0xffff);}return((dvp->data) & 0xff);}Example 8.5The rules about mixing volatile and regular types resemble those for const. A pointer to a volatile object can be assigned the address of a regular object with safety, but it is dangerous (and needs a cast) to take the address of a volatile object and put it into a pointer to a regular object. Using such a derived pointer results in undefined behaviour.If an array, union or structure is declared with const or volatile attributes, then all of the members take on that attribute too. This makes sense when you think about it—how could a member of a const structure be modifiable?That means that an alternative rewrite of the last example would be possible. Instead of declaring the device registers to be volatile in the structure, the pointer could have been declared to point to a volatile structure instead, like this:struct devregs{unsigned short csr; /* control & status */unsigned short data; /* data port */};volatile struct devregs *const dvp=DEVADDR+devno;Since dvp points to a volatile object, it not permitted to optimize references through the pointer. Our feeling is that, although this would work, it is bad style. The volatile declaration belongs in the structure: it is the device registers which are volatile and that is where the information should be kept; it reinforces the fact for a human reader.So, for any object likely to be subject to modification either by hardware or asynchronous interrupt service routines, the volatile type qualifier is important.Now, just when you thought that you understood all that, here comes the final twist. A declaration like this:volatile struct devregs{/* stuff */}v_decl;declares the type struct devregs and also a volatile-qualified object of that type, called v_decl. A later declaration like thisstruct devregs nv_decl;declares nv_decl which is not qualified with volatile! The qualification is not part of the type of struct devregs but applies only to the declaration of v_decl. Look at it this way round, which perhaps makes the situation more clear (the two declarations are the same in their effect):struct devregs{/* stuff */}volatile v_decl;If you do want to get a shorthand way of attaching a qualifier to another type, you can use typedef to do it:struct x{int a;};typedef const struct x csx;csx const_sx;struct x non_const_sx = {1};const_sx = non_const_sx; /* error - attempt to modify a const */ 8.4.2.1. Indivisible OperationsThose of you who are familiar with techniques that involve hardware interrupts and other ‘real time’ aspects of programming will recognise th e need for volatile types. Related to this area is the need to ensure that accesses to data objects are ‘atomic’, or uninterruptable. To discuss this is any depth would take us beyond the scope of this book, but we can at least outline some of the issues.Be careful not to assume that any operations written in C are uninterruptable. For example,extern const volatile unsigned long realtimeclock;could be a counter which is updated by a clock interrupt routine. It is essential to make it volatile because of the asynchronous updates to it, and it is marked const because it should not be changed by anything other than the interrupt routine. If the program accesses it like this:unsigned long int time_of_day;time_of_day = real_time_clock;there may be a problem. What if, to copy one long into another, it takes several machine instructions to copy the two words making up real_time_clock and time_of_day? It is possible that an interrupt will occur in the middle of the assignment and that in the worst case, when the low-order word ofreal_time_clock is 0xffff and the high-order word is 0x0000, then the low-order word of time_of_day will receive 0xffff. The interrupt arrives and increments the low-order word of real_time_clock to 0x0 and then the high-order word to 0x1, then returns. The rest of the assignment then completes, with time_of_day ending up containing 0x0001ffff and real_time_clock containing the correct value, 0x00010000.This whole class of problem is what is known as a critical region, and is well understood by those who regularly work in asynchronous environments. It should be understood that Standard C takes no special precautions to avoid these problems, and that the usual techniques should be employed.The header ‘signal.h’ declares a type called sig_atomic_t which is guaranteed to be modifiable safely in the presence of asynchronous events. This means only that it can be modified by assigning a value to it; incrementing or decrementing it, or anything else which produces a new value depending on its previous value, is not safe.下面是一篇专门讲volatile的Use of volatileThe compilation system tries to reduce code size and execution time on all machines, by optimizing code. It is programmer responsibility to inform compilation system that certain code (or variable) should not be optimized. Many programmers do not understand when to use volatile to inform compilation system that certain code should not be optimized or what it does. Although (no doubt) their program work, they do not exploit the full power of the language.A variable should be declared volatile whenever its value can be changed by something beyond the control of the program in which it appears, such as a concurrently executing thread. Volatile, can appear only once in a declaration with any type specifier; however, they cannot appear after the first comma in a multiple item declaration. For example, the following declarations are legal/* Let T denotes some data type */typedef volatile T i;volatile T i;T volatile i ;And the following declaration is illegalT i, volatile vi ;Volatile qualifiers can be used to change the behavior of a type. For example,volatile int p = 3;declares and initializes an object with type volatile int whose value will be always read from memory.SyntaxKeyword volatile can be placed before or after the data type in the variable definition. For example following declaration are identical:Volatile T a =3;T volatile a=3;The declaration declares and initializes an objet with type volatile T whose value will be always read from memoryPointer declarationVolatile T * ptr;T volatile * ptr;Ptr is a a pointer to a volatile T:volatile pointer to a volatile variableint volatile * volatile ptr;volatile can be applied to derived types such as an array type ,in that case, the element is qualified, not the array type. When applied to struct types entire contents of the struct become volatile. You can apply the volatile qualifier to the individual members of the struct. Type qualifiers are relevant only when accessing identifiers as l-values in expressions. volatile does not affects the range of values or arithmetic properties of the object.. To declare the item pointed to by the pointer as volatile, use a declaration of the form:volatile T *vptr;To declare the value of the pointer - that is, the actual address stored in the pointer - as volatile, use a declaration of the form:T* volatile ptrv;Use of volatile- An object that is a memory-mapped I/O port- An object variable that is shared between multiple concurrent processes- An object that is modified by an interrupt service routine- An automatic object declared in a function that calls setjmp and whose value is-changed between the call to setjmp and a corresponding call to longjmp# An object that is a memory-mapped I/O portan 8 bit , memory -mapped I/O port at physical address 0X15 can be declared aschar const ptr=(char*)0X15 ;*ptr access the port consider following code fragment to set the third bit of the output port at periodic intervals*ptr = 0;while(*ptr){*ptr = 4 ;*ptr = 0 ;}the above code may be optimize as*ptr = 0while(0) {}*ptr is assigned 0 before value 4 is used ( and value of *ptr never changes ( same constant is always assigned to it)volatile keyword is used to suppress these optimization the compiler assumes that the value can change any time , even if no explicit code modify it to suppress all optimization declare ptr asvolatile char * const ptr = (volatile char*)0x16this declaration say the object at which ptr points can change without notice , but that ptr itself is a constant whose value never change# An object that is shared between multiple concurrent processesif two threads/tasks concurrently assign distinct values to the same shared non-volatile variable, a subsequent use of that variable may obtain a value that is not equal to either of the assigned values, but someimplementation-dependent mixture of the two values. so a global variable references by multiple thread programmers must declare shared variable as volatile.#include#includevolatile int num ;void* foo(){while(1) {++num ;sleep(1000);}}main(){int p ;void *targ =NULL ;thread_t id ;num = 0;p = thr_create((void*)NULL , 0,foo,targ,0,&id);if(!p) printf(" can not create thread ");while(1){printf("%d" , num ) ;}}the compiler may use a register to store the num variable in the main thread , so the change to the value by the second thread are ignored . The volatile modifier is a away of telling the compiler that no optimization applied to the variable its value be not placed in register and value may change outside influence during evaluation# An automatic object declared in a function that calls setjmp and whose value is-changed between the call to setjmp and a corresponding call to longjmpVariables local to functions that call setjmp is most often used. When an automatic object is declared in a function that calls setjmp, the compilation system knows that it has to produce code that exactly matches what the programmer wrote. Therefore, the most recent value for such an automatic object will always be in memory (not just in a register) and as such will be guaranteed to be up-to-date when longjmp is called. Without volatile variable is undefined by the standard whether the result one see differs with or without optimization simply reflects that fact Consider following code#includestatic jmp_buf buf ;main( ){volatile int b;b =3 ;if(setjmp(buf)!=0) {printf("%d ", b) ;exit(0);}b=5;longjmp(buf , 1) ;}volatile variable isn't affected by the optimization. So value of b is after the longjump is the last value variable assigned. Without volatile b may or may notbe restored to its last value when the longjmp occurs. For clear understanding assembly listing of above program by cc compiler has been given below./*Listing1: Assembly code fragment of above programProduced by cc compiler when volatile is used*/.file "vol.c"main:pushl %ebpmovl %esp, %ebpsubl $20, %espmovl $3, -4(%ebp)pushl $bufcall _setjmpaddl $16, %esptestl %eax, %eaxje .L18subl $8, %espmovl -4(%ebp), %eaxpushl %eaxpushl $.LC0call printfmovl $0, (%esp)call exit.p2align 2.L18:movl $5, -4(%ebp)subl $8, %esppushl $1pushl $bufcall longjmp/*Listing 2:Assemply code fragment of above programproduced by cc compile witout volatile keword */.file "wvol.c"main:pushl %ebpmovl %esp, %ebpsubl $20, %esppushl $bufcall _setjmpaddl $16, %esptestl %eax, %eaxje .L18subl $8, %esppushl $3pushl $.LC0call printfmovl $0, (%esp)call exit.p2align 2.L18:subl $8, %esppushl $1pushl $bufcall longjmp/listing 3: difference between listing 1 and listing 3 ***/< .file "vol.c"---> .file "wvol.c"< movl $3, -4(%ebp)< movl -4(%ebp), %eax< pushl %eax> pushl $3< movl $5, -4(%ebp) / * store in stack */From above listing 3 it is clear that when you use setjmp and longjmp, the only automatic variables guaranteed to remain valid are those declared volatile.# An object modified by an interrupt service routineInterrupt service routines often set variables that are tested in main line code. One problem that arises as soon as you use interrupt is that interrupt routines need to communicate with rest of the code .A interrupt may update a variable num that is used in main line of code .An incorrect implementation of this might be:static lon int num ;void interrupt update(void){++num ;}main(){long val ;val = num ;while(val !=num)val = num ;rturn val ;}When compilation system execute while statement, the optimizer in compiler may notice that it read the value num once already and that value is still in the register. Instead of re reading the value from memory, compiler may produce code to use the (possibly messed up) value in the register defeating purpose of original C program. Some compiler may optimize entire while loop assuming that since the value of num was just assigned to val , the two must be equal and condition in while statement will therefore always be false .To avoid this ,you have to declare num to be volatile that warns compilers that certain variables may change because of interrupt routines.static volatile long int num ;With volatile keyword in the declaration the compiler knows that the value of num must b read from memory every time it is referenced.ConclusionWhen using exact semantics is necessary, volatile should be used. If you are given a piece of touchy code given as above. It is a good idea in any case to look the compiler outputting listing at the assembly language to be sure that compiler produce code that makes sense.。
c++ volatile用法
c++ volatile用法C++中,关键字volatile用于标记一个对象为易变的(volatile object),其值可能被意外或非顺序的方式改变。
大多数情况下,对象的改变都是通过执行一个操作而引起的(如写入内存或寄存器)。
有些可能会改变对象的值的过程无法通过编译器以及程序员了解,这种情况下就需要使用volatile关键字。
本文将会介绍volatile的用法及其注意事项。
1. volatile的使用方式在C++中,关键字volatile有以下两种用法:1)对于一个变量或对象,加上关键字volatile时,意义是告诉编译器该变量或对象是可能被意外更改的。
例如:```cppvolatile int counter;```上面这段代码表明,counter变量可能会在程序执行时被意外更改,比如被其他线程修改。
为了保证读取到counter的值的正确性,我们需要在所有有可能访问该变量的地方都加上volatile的关键字。
2)在函数参数中使用关键字volatile时,表示该参数的指针是可用于访问可更改的内存块(例如硬件寄存器)的。
例如:```cppvoid function(volatile int *ptr);```上面这个函数声明表明,该函数可能更改指针ptr指向的内存块的值。
由于volatile 关键字阻止编译器优化掉代码以最大限度地利用寄存器,因此该函数应该尽量避免调用频繁或性能要求高的情况。
2. volatile的实现方式volatile在底层的实现方式是通过在对应的机器指令中加入一些特殊的处理指令,表示该指令不能被优化或重排,必须按程序顺序执行。
3. volatile的注意事项1)不要将volatile用于所有地方虽然volatile可以强制编译器不对程序优化,但是过度使用或误用volatile会导致程序运行效率降低,甚至产生一些未知的错误。
我们应该尽可能地使用const关键字替代volatile,只在必须要使用volatile时才使用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例如: volatilFra bibliotek int i=10;
int j = i;
...
int k = i;
volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。
而优化做法是,由于编译器发现两次从i读搜索数据
__O :输出口,也不能进行优化,不然你连续两次输出相同值,编译器认为没改变,就忽略了后面那一次输出,假如外部在两次输出中间修改了值,那就影响输出
__IO:输入输出口,同上
为什么加下划线?
原因是:避免命名冲突
一般宏定义都是大写,但因为这里的字母比较少,所以再添加下划线来区分。这样一般都可以避免命名冲突问题,因为很少人这样命名,这样命名的人肯定知道这些是有什么用的。
#define __IO volatile /*!< defines 'read / write' permissions */
volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。
__I、 __O 、__IO是什么意思?
这是ST库里面的宏定义,定义如下:
#define __I volatile const /*!< defines 'read only' permissions */
#define __O volatile /*!< defines 'write only' permissions */
的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。
__I :输入口。既然是输入,那么寄存器的值就随时会外部修改,那就不能进行优化,每次都要重新从寄存器中读取。也不能写,即只读,不然就不是输入而是输出了。
经常写大工程时,都会发现老是命名冲突,要不是全局变量冲突,要不就是宏定义冲突,所以我们要尽量避免这些问题,不然出问题了都不知道问题在哪里。