一. 存储介质对比
特性 | 寄存器(Register) | 缓存(Cache) | RAM(随机存取内存) | Flash(闪存) | ROM(只读存储器) |
---|---|---|---|---|---|
位置 | CPU 内部 | CPU 内部,或 CPU 与内存之间 | 主内存,位于主板或外部存储设备中 | 外部存储设备(如 USB、SSD、嵌入式芯片) | 外部存储设备(如 ROM 芯片) |
容量 | 极小(几字节到几十字节) | 较大(几 KB 到几 MB) | 较大(几 GB,通常为几 GB 到几十 GB) | 较大(几 MB 到几 GB) | 小到中(几 KB 到几 MB) |
速度 | 极快(与 CPU 同速) | 快(比 RAM 快,但比寄存器慢) | 较慢(比缓存快,但比 Flash 慢) | 较慢(毫秒级,通常是块级写入) | 很慢(几毫秒到几百毫秒) |
可访问性 | 直接由 CPU 操作,无延迟 | 自动管理,硬件控制 | CPU 直接访问,可能有延迟 | 通过特定接口访问(如 IDE, USB) | 主要用于存储固化程序,通常是只读 |
易失性 | 易失性(断电数据丢失) | 易失性(断电数据丢失) | 易失性(断电数据丢失) | 非易失性(数据断电后不会丢失) | 非易失性(数据断电后不会丢失) |
用途 | 存储临时数据、指令、运算中间结果 | 存储频繁访问的内存数据,加速内存访问 | 存储正在运行的程序和数据 | 存储固化的程序、文件、配置数据 | 存储固化程序(如引导程序、固件等) |
控制方式 | 由 CPU 指令直接控制 | 由硬件自动管理,根据访问模式存储数据 | 操作系统管理,CPU 直接读写 | 操作系统或设备控制,通过接口进行访问 | 只读,通常出厂时写入,无法修改(除非特殊设计,如 EEPROM) |
示例 | 程序计数器(PC),通用寄存器(GPRs) | L1、L2、L3 缓存 | DDR RAM、SDRAM 等 | USB 驱动器、固态硬盘(SSD)、eMMC | BIOS、引导程序、嵌入式固件等 |
二. volatile关键字
关键字作用
“volatile” 关键字一般在编程中(特别是C/C++、Java等语言里)用来修饰变量,主要有以下几个作用:
-
防止编译器优化:编译器在优化代码时,可能会把变量缓存到寄存器或者做其他假设,认为变量的值不会被其他线程或硬件意外修改。用volatile修饰后,告诉编译器该变量可能会被意外修改,禁止对其进行优化缓存,确保每次访问都是直接从内存读取。
-
保证变量的可见性:在多线程环境下,一个线程对volatile变量的修改,会立即对其他线程可见,避免线程读取到变量的旧值。volatile确保线程之间的内存可见性。
-
防止指令重排序:在某些语言和架构中,volatile还能对编译器和处理器的指令重排序起到一定限制作用,保证操作顺序。
关键字使用场景
场景 | 使用 volatile 的原因 |
---|---|
多线程共享变量 | 保证变量对其他线程的可见性 |
访问硬件寄存器 | 硬件自动修改内存,程序需及时读取新值 |
信号处理函数修改变量 | Unix/Linux:程序需检测信号处理函数(signal handler)对变量的修改 |
避免某些编译器优化与重排序 | 保证代码执行顺序符合预期 |
与外部事件(设备、I/O)交互 | 保证程序读取的是最新的外部状态 |
场景一举例
#include <stdio.h>
#include <windows.h>
volatile int flag = 0; // 用volatile修饰,防止编译器优化
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
printf("线程等待 flag 变为1...\n");
while (flag == 0) {
// 空循环等待
// 没有volatile的话,这里可能被优化成死循环
}
printf("flag = 1,线程继续执行\n");
return 0;
}
int main() {
HANDLE hThread;
DWORD threadId;
// 创建线程
hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &threadId);
if (hThread == NULL) {
printf("创建线程失败\n");
return 1;
}
printf("主线程休眠2秒...\n");
Sleep(2000);
printf("主线程设置flag=1\n");
flag = 1; // 改变flag,线程看到后结束循环
// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
printf("程序结束\n");
return 0;
}