如何在Linux GCC下用C11 <stdatomic.h>实现int变量原子读写?
在Linux+GCC下用C11 <stdatomic.h>实现int原子读写的最简方案
嘿,这个问题抓得特别准——多线程里随便假设普通变量读写是原子的,绝对是踩坑的常客!好在C11的<stdatomic.h>给了标准的解决方案,结合GCC在Linux下的支持,实现起来其实很直接。
我一步步给你拆解:
1. 先把普通int改成原子类型
首先,你不能再用普通的int来声明messageBox了,得换成标准原子类型atomic_int。这是基础,因为只有原子类型的操作才能被编译器和硬件保证原子性:
#include <stdatomic.h> // 把原来的int数组改成atomic_int数组 atomic_int messageBox[YOUR_SIZE];
如果是全局变量或者静态变量,初始化可以用ATOMIC_VAR_INIT宏:
atomic_int messageBox[5] = {ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0), ...};
2. 原子赋值操作(替换messageBox[i] = 2)
普通的赋值=对于原子类型虽然GCC可能允许,但标准里更推荐用atomic_store函数来明确表达原子写入的意图,避免编译器优化出问题:
// 原子写入值2到messageBox[i],默认用最严格的内存顺序(memory_order_seq_cst) atomic_store(&messageBox[i], 2);
如果你对内存顺序有更轻量的需求(比如不需要全局的内存可见性排序),可以指定第三个参数,比如memory_order_relaxed,但新手阶段用默认的seq_cst最安全,不会因为内存模型的细节踩坑。
3. 原子读取+判断操作(替换if (messageBox[i] == 2))
同样,不能直接读取原子变量的内容,要用atomic_load来做原子读取:
// 原子读取messageBox[i]的值,然后判断是否等于2 if (atomic_load(&messageBox[i]) == 2) { // 你的逻辑代码 }
这里atomic_load同样默认用memory_order_seq_cst,保证读取到的是最新的、其他线程写入的值。
完整小例子
给你写个简单的多线程示例,一个线程写原子变量,另一个线程读:
#include <stdio.h> #include <pthread.h> #include <stdatomic.h> #define BOX_SIZE 3 atomic_int messageBox[BOX_SIZE] = {ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0)}; void* writer_thread(void* arg) { int idx = *(int*)arg; // 原子赋值 atomic_store(&messageBox[idx], 2); printf("Writer thread: set messageBox[%d] to 2\n", idx); return NULL; } void* reader_thread(void* arg) { int idx = *(int*)arg; // 循环等待直到读取到2 while (atomic_load(&messageBox[idx]) != 2) { // 可以加个sleep或者空循环,这里为了简化用空循环 } printf("Reader thread: detected messageBox[%d] is 2\n", idx); return NULL; } int main() { pthread_t writer, reader; int idx = 1; pthread_create(&writer, NULL, writer_thread, &idx); pthread_create(&reader, NULL, reader_thread, &idx); pthread_join(writer, NULL); pthread_join(reader, NULL); return 0; }
编译的时候记得加上-std=c11(或者-std=gnu11如果你需要GNU扩展)和-pthread链接线程库:
gcc -std=c11 -pthread atomic_demo.c -o atomic_demo
额外提醒
- GCC从4.7版本开始支持C11的<stdatomic.h>,所以确保你的编译器版本足够新。
- 原子操作的内存顺序是个进阶知识点,如果你的场景对性能要求极高,可以研究
memory_order_relaxed、memory_order_acquire/memory_order_release等,但新手先坚持默认的seq_cst就好,正确性优先。 - 不要试图自己用
volatile来模拟原子操作——volatile只能防止编译器优化,但不保证硬件层面的原子性和内存可见性,完全是两回事!
内容的提问来源于stack exchange,提问作者Theo d'Or
相关产品推荐
相关产品推荐

