1.volatile关键字是什么
在c
和c++
中,volatile
关键字用于告诉编译器,变量的值可能会在程序执行期间被意外地改变,因此编译器不应该进行优化。
volatile int i = 10;
volatile int i = 11;
volatile int i = 12;
通过对变量加入volatile
关键字特征修饰符可以保证变量i
在程序运行过程中每条指令都被正确地执行。
2.volatile的作用
2.1 防止被编译器优化
编译器在编译代码时会对代码优化提高程序的执行效率。编译期可能会将一些常量或者变量的值缓存到寄存器中以便快速访问。
当程序处于多线程编程和信号处理的场景下时,变量的值可能被意外地改变导致程序出现错误。
int i = 0;
while(i < 10){
std::cout << "" << std::endl;
i++;
}
虽然在循环中,变量i
的值确实会被更新,但是编译器可能会把i
的值缓存到寄存器中,导致循环无法正常退出。
通过引入volatile
关键字可以解决这一问题。
volatile int i = 0;
while(i < 10){
std::cout << "" << std::endl;
i++;
}
在这个代码中,使用volatile
关键字告诉编译器,变量count
的值可能被意外地改变,因此编译器不应该对该变量进行优化。
2.2 多线程同步
在多线程编程中,多个线程可能同时访问同一个变量。如果变量的值被缓存到寄存器中,就会导致线程之间的数据不一致。
volatile int count = 0;
pthread_t threads[10];
void* thread_func(void* arg) {
while (count < 10) {
printf("%d\n", count);
count++;
}
return NULL;
}
void main()
{
for (int i = 0; i < 10; i++)
{
pthread_create(&threads[i], NULL, thread_func, NULL);
}
for (int i = 0; i < 10; i++)
{
pthread_join(threads[i], NULL);
}
return;
}
当前代码启动了 10 个线程,每个线程都会访问变量 count 并对其进行更新。如果变量 count 的值被缓存到寄存器中,就会导致线程之间的数据不一致。
因此需要使用volatile
关键字告诉编译器,变量count
的值可能被意外地改变,因此编译器不应该对变量进行优化。
2.3 对寄存器的访问
在嵌入式编程中,因为需要经常访问硬件寄存器,由于硬件寄存器的值可能会被意外地改变,因此需要使用volatile
关键字来告诉编译器,变量的值可能会被意外地改变。
#define GPIO_BASE 0x12345678
volatile unsigned int* gpio = (volatile unsigned int*)GPIO_BASE;
void set_gpio(unsigned int value)
{
*gpio = value;
}
unsigned int get_gpio()
{
return *gpio;
}
这段代码中,定义了一个指针gpio
指向硬件寄存器的地址,由于硬件寄存器的值可能被意外改变,因此使用volatile
关键字来告诉编译器,该值在运行期间可能被动态改变多次,不要进行优化。
3.volatile关键字的注意事项
①在C语言中volatile
关键字只能用于变量,不能用于函数、结构体。
②在C语言中volatile
关键字不能用于指针类型,因为指针类型本身就是一个地址,没有值可以被缓存。
③在C语言中volatile
关键字不能保证线程安全,因为它只能防止编译器优化,不能保证多个线程之间的数据一致性。
- 参考示例
stm32函数库底层的寄存器定义就是加了volatile的
参考链接
https://baijiahao.baidu.com/s?id=1766831734273806604&wfr=spider&for=pc
【C语言volatile关键字详解】https://blog.csdn.net/u010134355/article/details/125058164