1

http://www.stroustrup.com/C++11FAQ.html#memory-model

the page describe that :

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

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

.....

However, most modern processors cannot read or write a single character, it must read or write a whole word, so the assignment to c really is ``read the word containing c, replace the c part, and write the word back again.'' Since the assignment to b is similar, there are plenty of opportunities for the two threads to clobber each other even though the threads do not (according to their source text) share data!

I have a struct :

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

and global vars:

data dx ; 
int x,y ;

Thread1 :

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

Thread2 :

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

Compiled at gcc 4.4.6 , and run it 1,000,000 times , look like I don't get any value that not (x==1 && y==1) !!!!

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

I put char c and char b in a structure aligned(2) on purpose so that they both belong to the same word , and according to the webpage describe , I might have the chance to get results not (x==1 && y==1) , the fact is that run the test 1,000,000 time , all get (x==1 && y==1) , is that because gcc do any tricks ? or something I missed ?

Edit :

Thread1 :

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 ;
}

Thread2 :

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 ;
}

Main :

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 :

I think I finally figure it out !!

struct { char c ; char b ;}

c and b would be different memory location , so that they can be thread-safe access !! the cpu can access single-byte char atomiclly !!!!!

I change code to :

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

and in main :

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

I observe there are results that not (dx.c==1)&&(dx.b==1) !! This is because the dx.c and dx.b is in the same memory location in this case !!!!

So I make a mistake , the most important thing to decide is memory location , struct {char c; char b;} , char c and char b is in different memory location , the test result is correct !!!!

4

1 回答 1

3

请参阅 C++ 标准中的 1.7 [intro.memory] ​​p3:

内存位置要么是标量类型的对象,要么是所有具有非零宽度的相邻位域的最大序列。[ 注意: ... ] 两个或多个执行线程 (1.10) 可以更新和访问单独的内存位置,而不会相互干扰。

因此,符合标准的编译器只需确保可以更新 char 而不会影响其他内存位置。

于 2013-11-04T09:27:49.130 回答