2013-11-04 71 views
1

http://www.stroustrup.com/C++11FAQ.html#memory-model存儲位置和數據競爭

的頁面描述:

// thread 1: 
char c; 
c = 1; 
int x = c; 

// thread 2: 
char b; 
b = 1; 
int y = b; 

.....

然而,最現代化的處理器不能讀取或寫入單個字符,它必須讀或寫一整個單詞,所以對c的賦值實際上是「讀取包含c的單詞,替換c部分,並再次將單詞寫回。」由於賦值給b類似,所以有很多這兩個線程的機會摧毀e即使線程不(根據它們的源文本)共享數據!

我有一個結構:

struct data_ 
{ 
    volatile char c ; 
    volatile char b ; 
} __attribute__((aligned(2))); 
typedef struct data_ data ; 

和全局變量:

data dx ; 
int x,y ; 

線程1:

dx.c = 1 ; 
    x = dx.c ; 

線程2:

dx.b = 1 ; 
    y = dx.b ; 

編譯在GCC 4.4.6,並運行100萬次, 樣子我沒有得到任何價值,不是(x == 1 & &Ÿ== 1)!!!!

struct data_ 
{ 
    volatile char c ; 
    volatile char b ; 
} __attribute__((aligned(2))); 

我把字符c和焦炭b在對齊的結構(2)故意使他們都屬於 同一個詞,並根據網頁的描述,我可能有機會 ,得到的結果不是(x == 1 & & y == 1),事實是,運行測試1,000,000次,所有得到(x == 1 & & y == 1),是因爲gcc做任何技巧?還是我錯過了什麼?

編輯:

線程1:

int ilocal ; 
while(1) 
{ 
    sem_wait(sem1) ; 
    dx.c = 1 ; 
    x = dx.c ; 
    ilocal = __sync_add_and_fetch(&icnt,1) ; 
    if(ilocal == 2) 
     sem_post(sem3) ; 
    ++icnt1 ; 
} 

線程2:

int ilocal ; 
while(1) 
{ 
    sem_wait(sem2) ; 
    dx.b = 1 ; 
    y = dx.b ; 
    ilocal = __sync_add_and_fetch(&icnt,1) ; 
    if(ilocal == 2) 
     sem_post(sem3) ; 
    ++icnt2 ; 
} 

主營:

int idx,iflag1=0,iflag2=0 ; 
for(idx=0;idx<1000000;idx++) 
{ 
    icnt = 0 ; dx.c=0 ; dx.b=0 ; 
    sem_post(sem1) ; 
    sem_post(sem2) ; 
    sem_wait(sem3) ; 
    if(! ((x==1)&&(y==1)) ) 
    { 
     printf("result that (x==%d && y==%d) \n",x,y) ; 
     ++iflag1 ; 
    }else{ 
     ++iflag2 ; 
    } 
} //while 
printf("iflag1=(%d),iflag2=(%d)\n",iflag1,iflag2) ; 
printf("icnt1=(%d),icnt2=(%d) \n",icnt1,icnt2) ; 

GCC memorylocate.c -lpthread -o memorylocate.exe

sizeof data=(64) //source already change to __attribute__((aligned(64)) 
iflag1=(0),iflag2=(1000000) 
icnt1=(1000000),icnt2=(1000000) 

EDIT2:

我想我終於弄明白!

struct { char c ; char b ;} 

c和b。將不同的內存位置,這樣他們可以是線程安全的訪問! 該CPU可以原子訪問單字節字符!!!!!

更改代碼:

struct data_ 
{ 
    unsigned char c:4 ; 
    unsigned char b:4 ; 
} ; 

和在主:

for(idx=0;idx<1000000;idx++) 
{ 
    icnt = 0 ; dx.c=0 ; dx.b=0 ; 
    sem_post(sem1) ; 
    sem_post(sem2) ; 
    sem_wait(sem3) ; 
    if(! ((dx.c==1)&&(dx.b==1)) ) 
    { 
     printf("result that (x==%d && y==%d) \n",x,y) ; 
     ++iflag1 ; 
    }else{ 
     ++iflag2 ; 
    } 
} //while 

我觀察有結果,不是(dx.c == 1)& &(dx.b == 1)!!這是因爲在這種情況下,dx.c和dx.b在同一個內存位置!!!!

所以我犯了一個錯誤,最重要的決定是內存位置,struct {char c; char b;},char c和char b在不同的內存位置,測試結果是正確的!

+0

這不僅僅是它們是否在同一個詞中,而是與您的高速緩存大小對齊以確保它們實際上也在同一高速緩存行中。 – kfsone

+0

@ kfsone,謝謝,改爲對齊(64),仍然得到相同的結果,你的意思是這只是一個虛假的共享問題? – barfatchen

+0

你有沒有將'dx.b'或'dx.c'更改爲1以外的值的代碼? – greatwolf

回答

3

看到在C++標準1.7 [intro.memory] ​​P3:

的存儲器位置或者是標量類型的對象或相鄰位字段都具有非零寬度的最大 序列。 [注意: ...]兩個或更多執行線程(1.10)可以更新和訪問單獨的內存位置,而不會相互干擾。

因此,一致性編譯器只需確保可以更新字符而不影響其他內存位置。

+1

...除非您使用非標準擴展來混亂對齊,在這種情況下,您必須查閱編譯器手冊以確保。 – ComicSansMS