关于向atomic_add传入非volatile变量及mmap指针的技术疑问
关于atomic_add函数的两个问题
背景代码
函数声明:
void atomic_add(volatile unsigned * loc, unsigned incr );
调用代码:
unsigned a; atomic_add(&a, 1); volatile unsigned b; atomic_add(&b, 1);
上述代码符合volatile类型限定符规则,可正常编译。
Q1:两次调用atomic_add的结果是否一致?
两次调用的原子加1操作本身的结果是一致的——不管传入的是普通unsigned变量的指针还是volatile unsigned变量的指针,atomic_add作为原子操作函数,都会保证对目标地址执行一次原子性的+1操作,最终a和b的值都会变成1。
不过两者存在细节区别:
- 对于非
volatile的变量a,编译器在其他未用volatile限定的代码中,可能会对a的值做缓存优化(比如存在寄存器中);但这两次atomic_add调用本身是直接操作内存的原子操作,不会受该优化影响。 - 对于
volatile的变量b,编译器会每次从内存读取其值,禁止缓存优化,这主要影响后续对b的非原子操作,不影响本次原子加的结果。
Q2:mmap()返回的指针能否作为该函数的第一个参数传入?
可以,但需要满足几个前提:
- 类型转换:
mmap返回的是void*,需要显式转换为volatile unsigned*类型后传入,示例代码:void* mapped_addr = mmap(NULL, sizeof(unsigned), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (mapped_addr != MAP_FAILED) { atomic_add((volatile unsigned*)mapped_addr, 1); } - 内存权限:
mmap映射时必须指定PROT_WRITE权限,否则原子加操作会触发内存访问错误。 - 地址对齐:
atomic_add的原子操作要求目标地址对齐到unsigned类型的自然边界(通常是4字节),而mmap返回的地址默认是页对齐的(一般为4KB或更大),完全满足对齐要求。
另外,mmap映射的设备内存或共享内存区域,本身就需要用volatile限定来防止编译器优化,和atomic_add的参数类型正好匹配。
内容的提问来源于stack exchange,提问作者sfzhang
相关产品推荐
相关产品推荐

