資料競爭

Version >= C11

C11 引入了對多執行緒執行的支援,這提供了資料競爭的可能性。程式包含資料競爭,如果其中的物件由兩個不同的執行緒訪問 1 ,其中至少一個訪問是非原子的,至少一個修改該物件,並且程式語義無法確保兩個訪問不能重疊時間。 2 請注意,所涉及的訪問的實際併發性不是資料競爭的條件; 資料競爭涵蓋了由不同執行緒的記憶體檢視中的(允許)不一致引起的更廣泛的問題。

考慮這個例子:

#include <threads.h>

int a = 0;

int Function( void* ignore )
{
    a = 1;

    return 0;
}

int main( void )
{
    thrd_t id;
    thrd_create( &id , Function , NULL );

    int b = a;

    thrd_join( id , NULL );
}

主執行緒呼叫 thrd_create 啟動一個新的執行緒執行函式 Function。第二個執行緒修改 a,主執行緒讀取 a。這些訪問都不是原子的,並且兩個執行緒無論是單獨還是聯合都不做任何事情以確保它們不重疊,因此存在資料競爭。

該計劃可以避免資料競爭的方式之一

  • 主執行緒可以在啟動另一個執行緒之前執行 a 的讀取;
  • 主執行緒在通過 thrd_join 確認對方已終止後,可以執行對 a 的讀取;
  • 執行緒可以通過互斥鎖同步它們的訪問,每個互斥鎖在訪問 a 之前鎖定該互斥鎖並在之後解鎖它。

正如互斥鎖選項所示,避免資料爭用不需要確保特定的操作順序,例如在主執行緒讀取之前修改 a 的子執行緒; 足以(避免資料競爭)確保對於給定的執行,一個訪問將在另一個之前發生。

1 修改或讀取物件。

2 (引自 ISO:IEC 9889:201x,第 5.1.2.4 節“多執行緒執行和
資料競爭”)如果程式的執行在不同的執行緒中包含兩個衝突的動作,其中至少有一個是不是原子的,也不會發生在另一個之前。任何此類資料爭用都會導致未定義的行為。