实例观察 c 语言中 volatile 的作用

volatile 意思是易变的。

在 c 语言中,如果变量被 volatile 修饰,就是告诉编译器这个变量随时都可能发生变化,那么每次读取变量的时候都会到内存中读取。

如果变量没有被 volatile 修饰,并且编译器发现在多次读取变量之间,变量没有被修改,那么编译器可能将变量的值保存到寄存器中,这样在后边访问变量的时候性能会得到提升。但是如果变量以编译器无法识别的方式被修改,那么这个时候将变量的值保存在寄存器中就可能引入问题。

1 volatile 使用场景

(1)硬件寄存器映射的内存地址

在嵌入是开发中,cpld 或者 fpga 中的寄存器可以映射到内存地址,直接通过内存地址来访问这些寄存器。这些寄存器的值可能会因硬件原因发生改变,这种情况是编译器无法识别的,所以需要 volatile 进行修饰。

(2)中断服务程序中会修改的,并且其它线程会访问的变量,需要使用 volatile 进行修饰。

(3)多线程应用中,多个线程共享的变量,需要使用 volatile 进行修饰。

volatile 是对编译器优化的补充。

在接触 volatile 之前,总会想当然的认为读取一个变量的时候就会去内存地址中读取。其实不不然,编译器会进行优化,如果在多次读取变量之间没有发现变量被修改,编译器可能将变量的值保存到寄存器中,这样后边的读取直接从寄存器中读取。从寄存器中读取相对于从内存中读取,性能大大提升。

但是编译器优化也不是万能的,当改变变量的方式,编译器无法识别的时候,那么编译器优化会导致问题。比如上边这 3 中场景,在这些场景下使用的变量,就需要使用 volatile 进行修饰。

2 实例观察有无 volatile 的区别

如下代码中,有一个全局变量 int flag,初始值是 1。

创建了两个线程 t1 和 t2,在 t1 中有一个 while() 循环,当 flag 的值为 1 的时候,循环继续;否则循环退出,并打印 "flag is not 1"。在 t2 中,将 flag 修改成了 0。

(1)int flag 被 volatile 修饰

编译命令:

gcc -O3 volatile.c -g

编译之后运行程序,会看到当 flag 被设置为 0 之后,t1 线程中的循环退出,并且打印了 "flag is not 1"。

(2)int flag 没有被 volatile 修饰

还是使用相同的命令进行编译。

编译之后运行程序,当 flag 被设置为 0 之后,看不到 t1 线程中的循环退出。

cpp 复制代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

volatile int flag = 1;

void *thread_entry(void *data) {
  while (flag == 1) {
    int tmp = flag;
  }
  printf("flag is not 1\n");
}


void *thread_entry1(void *data) {
  int *p = (int *)data;
  *p = 0;
  printf("after set flag to 0\n");
}


int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, thread_entry, NULL);

  sleep(10);
  pthread_t t2;
  pthread_create(&t2, NULL, thread_entry1, &flag);

  sleep(100);
  return 0;
}

通过上边两个实验,我们可以看出来加 volatile 和不加 volatile 的区别,与前边分析的一致。

我们通过将可执行文件进行反汇编,通过汇编指令来分析加 volatile 和不加 volatile 之间的区别。

有 volatile 修饰:

从汇编指令中可以看出来,while() 循环,在 1248 到 1257 指令之间循环执行,每次执行的时候,都会到内存中读取 flag 的值。

无 volatile 修饰:

从汇编指令可以看出,while() 循环中,编译器只在 1234, 123b 两个指令中从内存中读取数据,然后进行比较,后边直接在 123d 这一条指令进行循环,并不是每次循环都从内存中读取数据。

相关推荐
AllData公司负责人3 分钟前
【亲测好用】实时开发平台能力演示
java·c语言·数据库
pcm1235673 分钟前
设计C/S架构的IM通信软件(3)
java·c语言·架构
zz34572981134 分钟前
C语言基础概念7
c语言·开发语言
二年级程序员44 分钟前
C 语言文件操作
c语言
小莞尔1 小时前
【51单片机】【protues仿真】 基于51单片机波形发生器系统
c语言·单片机·嵌入式硬件·物联网·51单片机
No0d1es2 小时前
电子学会青少年软件编程(C语言)等级考试试卷(二级)2025年12月
c语言·青少年编程·等级考试·电子学会·二级
皮皮哎哟2 小时前
数据结构:从队列到二叉树基础解析
c语言·数据结构·算法·二叉树·队列
一匹电信狗2 小时前
【高阶数据结构】并查集
c语言·数据结构·c++·算法·leetcode·排序算法·visual studio
进击的小头2 小时前
设计模式组合应用:传感器数据采集与处理系统
c语言·设计模式
日拱一卒——功不唐捐2 小时前
01背包(C语言)
c语言