2012-11-24 64 views
2

AFAIK有pthread函數充當內存障礙(例如,這裏是clarifications-on-full-memory-barriers-involved-by-pthread-mutexes)。但編譯時障礙,即編譯器(尤其是gcc)是否意識到這一點?換句話說 - 例如, - 是pthread_create()gcc不執行重新排序的原因?編譯時間障礙 - 編譯器代碼重新排序 - gcc和pthreads

例如代碼:

a = 1; 
pthread_create(...); 

是不是一定重新排序將不會發生?
什麼不同的功能調用:

void fun(void) { 
    pthread_create(...); 
    ... 
} 

a = 1; 
fun(); 

是有趣的()也編譯時屏障(假設在pthread_create()是)?
不同翻譯單位的功能如何?

請注意,我對gcc和pthreads的一般行爲規範感興趣,不一定需要x86特定的(各種不同的嵌入式平臺)。
我對其他編譯器/線程庫行爲也不感興趣。

回答

3

因爲諸如pthread_create()之類的函數是外部函數,所以編譯器必須確保在調用該函數之前必須完成外部函數可以看到的任何副作用(例如寫入全局變量)。假設a是全局的或其他可能在外部可訪問的,編譯無法將寫入重新排序到a,直到在第一種情況下函數調用之後)。

這是任何C編譯器都需要的行爲,並且與線程真的沒有多大關係。但是,如果變量a是一個局部變量,編譯器可能能夠重新排序它,直到函數調用(a甚至可能根本就不存在於內存中)爲止,除非類似地址a被採取並以某種方式在外部可用(如將它作爲線程參數傳遞)。

例如:

int a; 

void foo(void) 
{ 
    a = 1; 
    pthread_create(...); // the compiler can't reorder the write to `a` past 
          // the call to `pthread_create()` 

    // ... 
} 


void bar(void) 
{ 
    int b; 
    b = 1; 
    pthread_create(...); // `b` can be initialized after calling `pthread_create()` 
          // `b` might not ever even exist except as a something 
          // passed on the stack or in a register to `printf()` 

    printf("%d\n", b); 
} 

我不知道,如果有,概述了對此進行了詳細的文檔 - 這是用C的主要覆蓋「彷彿」的規則。在5.1.2.3/3「程序執行」中的C99中。 C由具有序列點的抽象機器指定,副作用必須完整,程序必須遵循該抽象機器模型,除非編譯器可以推斷不需要副作用。

在我foo()上面的例子中,編譯器通常不能夠推斷出設置a = 1;不需要通過pthread_create(),因此設置a的價值1的副作用,必須在調用pthread_create()前完成。請注意,如果有執行全局優化的編譯器可以推斷a未在別處使用,則它們可能會延遲或延遲分配。但是,在這種情況下,沒有其他人正在使用副作用,所以不會有任何問題。

+0

變量是否具有內部或外部鏈接(靜態vs外部)有關係嗎? – Andy

+1

在內部聯繫的主要變量可以被視爲與當地人類似。但是,如果它們即使是間接也可以外部訪問,那麼編譯器將不得不像它們一樣對待全局變量。例如,如果你的線程函數使用'static'變量,那麼它可以從外部間接訪問,因爲線程函數是從'outside'調用的(這可以被編譯器檢測到,因爲指向線程函數的指針被傳遞給外部功能)。 –

+0

我真的不知道你最後的評論。恕我直言,靜態變量可以由線程通過其他外部函數間接使用(在線程創建之前獲取指向靜態a的指針)。 但是我正在尋找更多的東西,正式的描述(例如,鏈接到海灣合作委員會文件,郵件列表張貼)規則重新排序時可以發生和什麼時候不能。 – Andy