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的赋值是相似的,即使线程没有(根据他们的源文本)共享数据,两个线程也有很多机会相互冲突!
我有一个结构:
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编译,并运行1,000,000次, 看起来我没有得到任何不值(x == 1&& y == 1)!!!!
struct data_
{
volatile char c ;
volatile char b ;
} __attribute__(( aligned(2) ));
我将char c和char 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可以原子访问单字节char !!!!!
我将代码更改为:
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)&amp;&amp;(dx.b == 1)!!这是因为在这种情况下dx.c和dx.b位于相同的内存位置!!!!
所以我犯了一个错误,最重要的是决定内存位置,struct {char c; char b;},char c和char b在不同的内存位置,测试结果是正确的!!!!
答案 0 :(得分:3)
参见C ++标准中的1.7 [intro.memory] p3:
内存位置是标量类型的对象或最大值 所有相邻位域的序列都具有非零宽度。 [ 注意: ...]两个或多个执行线程(1.10)可以更新和访问 分开的存储位置而不会相互干扰。
因此,符合标准的编译器必须确保可以更新char而不影响其他内存位置。