C語言原子操作的實現(xiàn)示例
原子操作是并發(fā)編程中的一個核心概念。讓我詳細解釋:
什么是原子操作?
原子操作是指在執(zhí)行過程中不會被中斷的操作,要么完全執(zhí)行,要么完全不執(zhí)行,不會出現(xiàn)部分執(zhí)行的狀態(tài)。
比喻理解
就像原子是不可分割的基本單位一樣,原子操作是不可分割的操作單位。
非原子操作的問題
先看一個非原子操作的例子:
int counter = 0;
// 這不是原子操作!
void increment() {
counter = counter + 1;
}在匯編層面,這通常分為三步:
mov eax, [counter] ; 1. 讀取counter到寄存器 inc eax ; 2. 寄存器值加1 mov [counter], eax ; 3. 寫回內(nèi)存
競態(tài)條件問題:
線程A:讀取counter=0
線程B:讀取counter=0
線程A:計算0+1=1
線程B:計算0+1=1
線程A:寫入counter=1
線程B:寫入counter=1 ← 結果應該是2,但實際是1!
C語言中的原子操作
C11標準引入的原子類型
#include <stdatomic.h>
// 聲明原子變量
atomic_int atomic_counter = ATOMIC_VAR_INIT(0);
// 原子操作
void increment_atomic() {
atomic_fetch_add(&atomic_counter, 1); // 原子加法
}
int main() {
atomic_counter = 5; // 原子存儲
int value = atomic_counter; // 原子加載
printf("Counter: %d\n", value);
return 0;
}常見的原子操作函數(shù)
基本操作
#include <stdatomic.h>
atomic_int counter = ATOMIC_VAR_INIT(0);
// 加載和存儲
int load_value = atomic_load(&counter); // 原子讀取
atomic_store(&counter, 42); // 原子寫入
// 交換操作
int old_value = atomic_exchange(&counter, 100); // 原子交換
// 比較交換(CAS - Compare And Swap)
int expected = 100;
if (atomic_compare_exchange_strong(&counter, &expected, 200)) {
printf("CAS成功: 舊值=%d, 新值=200\n", expected);
}算術運算
// 原子加法 int old = atomic_fetch_add(&counter, 5); // counter += 5,返回舊值 // 原子減法 atomic_fetch_sub(&counter, 3); // counter -= 3 // 原子自增/自減 atomic_fetch_add(&counter, 1); // counter++ atomic_fetch_sub(&counter, 1); // counter--
位運算
atomic_int flags = ATOMIC_VAR_INIT(0); // 原子位操作 atomic_fetch_or(&flags, 0x01); // flags |= 0x01 atomic_fetch_and(&flags, ~0x01); // flags &= ~0x01 atomic_fetch_xor(&flags, 0x03); // flags ^= 0x03
原子操作的實際例子
1. 無鎖計數(shù)器
#include <stdatomic.h>
#include <pthread.h>
#include <stdio.h>
atomic_int counter = ATOMIC_VAR_INIT(0);
void* worker(void* arg) {
for (int i = 0; i < 100000; i++) {
atomic_fetch_add(&counter, 1); // 原子自增
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("最終計數(shù): %d (應該是200000)\n", atomic_load(&counter));
return 0;
}2. 自旋鎖實現(xiàn)
#include <stdatomic.h>
typedef atomic_flag spinlock_t;
void spinlock_init(spinlock_t* lock) {
atomic_flag_clear(lock);
}
void spinlock_lock(spinlock_t* lock) {
// 忙等待,直到獲得鎖
while (atomic_flag_test_and_set(lock)) {
// 可選的:減少CPU占用
// __builtin_ia32_pause(); // x86的PAUSE指令
}
}
void spinlock_unlock(spinlock_t* lock) {
atomic_flag_clear(lock);
}3. 無鎖棧(Lock-Free Stack)
#include <stdatomic.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
typedef struct {
_Atomic(Node*) top;
} LockFreeStack;
void stack_init(LockFreeStack* stack) {
atomic_store(&stack->top, NULL);
}
void stack_push(LockFreeStack* stack, int value) {
Node* new_node = malloc(sizeof(Node));
new_node->data = value;
Node* old_top;
do {
old_top = atomic_load(&stack->top);
new_node->next = old_top;
} while (!atomic_compare_exchange_weak(&stack->top, &old_top, new_node));
}
int stack_pop(LockFreeStack* stack) {
Node* old_top;
Node* new_top;
do {
old_top = atomic_load(&stack->top);
if (old_top == NULL) return -1; // ???
new_top = old_top->next;
} while (!atomic_compare_exchange_weak(&stack->top, &old_top, new_top));
int value = old_top->data;
free(old_top);
return value;
}內(nèi)存順序(Memory Order)
原子操作還涉及內(nèi)存可見性問題:
#include <stdatomic.h>
atomic_int data = ATOMIC_VAR_INIT(0);
atomic_int flag = ATOMIC_VAR_INIT(0);
// 生產(chǎn)者線程
void producer() {
atomic_store_explicit(&data, 42, memory_order_relaxed);
atomic_store_explicit(&flag, 1, memory_order_release); // 釋放語義
}
// 消費者線程
void consumer() {
while (atomic_load_explicit(&flag, memory_order_acquire) == 0) {
// 等待
}
int value = atomic_load_explicit(&data, memory_order_relaxed);
printf("Data: %d\n", value); // 保證看到42
}不同平臺的原生原子操作
x86架構
// 內(nèi)聯(lián)匯編實現(xiàn)原子操作
int atomic_increment(int* value) {
__asm__ __volatile__(
"lock incl %0" // lock前綴確保原子性
: "+m" (*value)
:
: "cc"
);
return *value;
}GCC內(nèi)置原子操作
int counter = 0;
// GCC內(nèi)置的原子操作
void increment_gcc() {
__sync_fetch_and_add(&counter, 1);
}
int compare_and_swap_gcc(int* ptr, int oldval, int newval) {
return __sync_val_compare_and_swap(ptr, oldval, newval);
}原子操作的優(yōu)缺點
優(yōu)點:
- 高性能:避免鎖的開銷
- 無死鎖:不會出現(xiàn)鎖順序問題
- 可擴展性:在多核系統(tǒng)中表現(xiàn)良好
缺點:
- 復雜性:正確實現(xiàn)很困難
- ABA問題:在CAS操作中可能出現(xiàn)
- 平臺依賴性:不同硬件支持程度不同
原子操作 vs 互斥鎖
| 特性 | 原子操作 | 互斥鎖 |
|---|---|---|
| 性能 | 高(硬件支持) | 中等(系統(tǒng)調(diào)用) |
| 復雜度 | 高 | 低 |
| 適用場景 | 簡單操作(計數(shù)器、標志位) | 復雜臨界區(qū) |
| 死鎖風險 | 無 | 有 |
| 可擴展性 | 好 | 一般 |
總結
原子操作是:
- 不可分割的操作單位
- 線程安全的,無需額外同步
- 硬件支持的,通常通過CPU指令實現(xiàn)
- 高性能的并發(fā)編程基礎
在現(xiàn)代多核處理器系統(tǒng)中,原子操作是實現(xiàn)高效并發(fā)程序的重要工具,特別是在實現(xiàn)無鎖數(shù)據(jù)結構、計數(shù)器、標志位等場景中。
到此這篇關于C語言原子操作的實現(xiàn)示例的文章就介紹到這了,更多相關C語言 原子操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C語言從strcpy到自定義字符串處理函數(shù)的原理解析
這篇文章主要介紹了C語言從strcpy到自定義字符串處理函數(shù)的相關資料,本文將從常見的字符串函數(shù)(如strcpy、strcat)入手,逐步深入探討字符串操作的核心原理,并引導你實現(xiàn)自定義字符串處理函數(shù),感興趣的朋友一起看看吧2025-05-05
Matlab實現(xiàn)繪制有氣泡感的網(wǎng)絡圖
這篇文章主要介紹了如何利用Matlab實現(xiàn)繪制有氣泡感的網(wǎng)絡圖,文中的示例代碼講解詳細,對我們學習Matlab有一定的幫助,需要的可以參考一下2023-02-02
詳解C語言gets()函數(shù)與它的替代者fgets()函數(shù)
這篇文章主要介紹了詳解C語言gets()函數(shù)與它的替代者fgets()函數(shù)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-10-10

