編譯器和CPU執行過程中,可能會生成或者執行的機器碼,可能和我們編寫的代碼的預期的邏輯不一樣,可能會造成一些問題。
單線程中,這樣沒有問題,因為編譯器和CPU可以保證即使有調整,但是最後的結果是預期的。
但在多線程的場景下,可能會有問題,本文隻關注多線程修改和通路同一個公共變量的場景。
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
static volatile int vvv = 1;
void * thread1(void *n){
sleep(2);
printf("sss\n");
vvv = -1;
return NULL;
}
int main() {
pthread_t t;
int re = pthread_create(&t, NULL, &thread1, NULL);
if(re < 0){
perror("thread");
}
while(vvv > 0){
__sync_synchronize ();
}
return 0;
}
如果沒有上面第6行或者第21行的代碼,并且編譯的時候用了-O3的優化選項,編譯器會将19 - 21的代碼優化成:
while(1){
}
是以可能導緻死循環。
volatile作用在編譯的時候,讓編譯器生成機器碼的時候,一方面,不做優化,老老實實按照代碼去翻譯,一方面,在運作的時候,被volatile修飾地變量不會被緩存到CPU的寄存器中,每次讀都是從記憶體中去讀。這樣可以解決上面代碼中的問題。
另外一種解決方式就是用形如__sync_synchronize(gcc和X86環境下) 這樣的函數,加一個邏輯上無實際意義的代碼,依照mem barrier的定義,此語句上面的語句會嚴格在下面語句之前執行,而且也讓編譯器的優化在此語句附近失效了,具體的細節需要檢視彙編代碼來檢視(TODO)。