關於c/c++中volatile的理解
背景
昨天新公司有同事分享了一個關於執行緒排程的主題,其中的一個細節談到多執行緒下的共享變數的訪問問題。有一個同事說,兩個或多個執行緒對同一個執行緒都能訪問的變數之所以不符合預期(比如說有2個執行緒,每個執行緒都對同一個全域性變數進行++操作10000次,那麼最終結果不一定是20000),是因為資料快取在cache,而執行緒做++操作時,不是從記憶體中讀取,而是從cache中讀取導致的。
我不認可他的說法,我認為根本原因是++操作不是原子操作,不能保證操作的原子性;因此做了一個小測試。
測試
直接看程式碼:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdint.h>
volatile int count = 0; // 或者是 int count = 0
void *test_func(void *arg)
{
int i=0;
for(i=0;i<10000000;++i)
{
//__sync_fetch_and_add(&count,1);
count++;
}
return NULL;
}
int main(int argc, const char *argv[])
{
pthread_t id[2];
int i = 0;
for(i=0;i<2;++i)
{
pthread_create(&id[i],NULL,test_func,NULL);
}
for(i=0;i<2;++i)
{
pthread_join(id[i],NULL);
}
printf("count = %d\n", count);
return 0;
}
結果:
可以發現,哪怕是在加了volatile之後,還是不能保證count等於20000000;根本原因就是count++操作並不是原子操作;線上程1取了count(假設此時count的值是100)做++的過程中(此時++還沒結束,count還是100),執行緒2來取count(此時count還是100),線上程1完成++操作後寫入了記憶體(此時記憶體中count的值是101),然後執行緒2頁完成了count++(執行緒2中的count也是101,此時執行緒2中的count是在暫存器中,而不是記憶體中)操作,也把count(從執行緒2的cpu的暫存器)寫入到記憶體中,count在記憶體中的值還是101——這樣的話,就會導致count的最終的值不是20000000;
原理
volatile的本質是什麼?它的設計初衷是什麼?應用場景又是哪些?
我看到一篇不錯的文章,連結如下:
C/C++ Volatile關鍵詞深度剖析
從彙編層面給出了volatile關鍵字新增之前的對比,從而確定volatile關鍵字的作用就是:
保證每次訪問變數時,都是從記憶體中讀取,而不是從cache或者說暫存器中直接使用;
此處還應該深挖一下,待補充!!!
結論
待補充!!!