日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C11原子操作

發(fā)布時間:2023/12/20 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C11原子操作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C11原子操作

C11原子操作API

在C11標準中,首次引入原子操作。

頭文件:stdatomic.h

標準定義了__STDC_NO_ATOMICS__宏,用來在編譯時檢測是否支持stdatomic。

同時還有一系列宏和函數(shù)用來判斷各種數(shù)據(jù)類型在當前的實現(xiàn)中是否支持原子操作,例如:ATOMIC_CHAR_LOCK_FREE,atomic_is_lock_free。

同時,標準定義了許多原子數(shù)據(jù)類型,例如:atomic_char,atomic_int。


初始化原子變量可以使用如下函數(shù),但不保證原子性(當然一般也不會在多線程中進行初始化)。

  • ATOMIC_VAR_INIT
  • atomic_init
  • ATOMIC_FLAG_INIT

操作原子變量則使用如下函數(shù),保證原子性

  • atomic_store
  • atomic_load
  • atomic_exchange
  • atomic_compare_exchange_strong, atomic_compare_exchange_weak
  • atomic_fetch_add, atomic_fetch_sub, atomic_fetch_or, atomic_fetch_xor, atomic_fetch_and
  • atomic_flag_test_and_set
  • atomic_flag_clear

gcc對原子操作的支持

在C11之前,gcc對原子操作的支持是通過builtin函數(shù)實現(xiàn)的,即__sync前綴的函數(shù)。

在C11發(fā)布之后,gcc通過stdatomic.h提供標準接口。gcc在4.9版本之后才正式、完備的支持stdatomic,在編譯命令中加上-std=c11或-std=gnu11即可。如果是之前的版本,那只能使用builtin函數(shù)了。


使用樣例

下面的例子開啟4個線程,每個線程都對全局變量sum執(zhí)行累加操作,如果不使用原子操作的話,最終輸出的sum值往往會比正確結(jié)果少:

#include <stdio.h> #include <pthread.h>int sum = 0;void *func(void *param) {for (int i = 0; i < 100000; ++i) {sum++;}return NULL; }int main() {pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, func, NULL);pthread_create(&t2, NULL, func, NULL);pthread_create(&t3, NULL, func, NULL);pthread_create(&t4, NULL, func, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t3, NULL);printf("sum = %d\n", sum);return 0; }

編譯執(zhí)行:

$ gcc sum1.c -o sum1 $ ./sum1 sum = 128093 $ ./sum1 sum = 276478 $ ./sum1 sum = 341649

即使把定義全局變量sum的地方改為volatile int sum = 0;依然不能解決問題,原因在于volatile關(guān)鍵字使得編譯器對生成的機器代碼不做優(yōu)化,每次訪問sum變量時必須訪問內(nèi)存而不是硬件寄存器。雖然如此,但連續(xù)兩次訪問sum變量仍然不是原子的。而sum++生成的機器代碼會先讀取sum到寄存器,寄存器加1后,再存回內(nèi)存,顯然不能保證原子性。


那要如何保證對sum++是原子性的呢?答案就是使用C11提供的原子操作。更改后的代碼如下:

#include <stdio.h> #include <pthread.h> #include <stdatomic.h>atomic_int sum = ATOMIC_VAR_INIT(0);void *func(void *param) {for (int i = 0; i < 100000; ++i) {atomic_fetch_add(&sum, 1);}return NULL; }int main() {pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, func, NULL);pthread_create(&t2, NULL, func, NULL);pthread_create(&t3, NULL, func, NULL);pthread_create(&t4, NULL, func, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);printf("sum = %d\n", atomic_load(&sum));return 0; }

可以看到,這里使用atomic_int類型來定義sum變量,使用atomic_fetch_add(&sum, 1);累加sum。

編譯運行看下:

$ gcc -std=c11 sum2.c -o sum2 $ ./sum2 sum = 400000 $ ./sum2 sum = 400000 $ ./sum2 sum = 400000 $ ./sum2 sum = 400000

多次運行程序sum結(jié)果都是正確的。

總結(jié)

以上是生活随笔為你收集整理的C11原子操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。