【发布时间】:2013-11-04 04:35:32
【问题描述】:
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 次, all get (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)
编辑2:
我想我终于弄明白了!!
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 在不同的内存位置,测试结果是正确的!!!!
【问题讨论】:
-
这不仅仅是它们是否在同一个单词中,还要根据您的缓存大小来确保它们实际上也在同一个缓存行中。
-
@kfsone,thanks,change to aligned(64) ,仍然得到相同的结果,你的意思是这只是一个虚假的分享问题?
-
您是否有将
dx.b或dx.c更改为1 以外的值的代码? -
@greatwolf ,是的,在主线程中设置 dx.b 和 dx.c 都为 0 ,并且信号量发布 thread1 和 thread2 运行,并从主线程获取结果,一直得到(x==1 && y==1)
-
@greatwolf ,我已经发布了 main 和 thread1,thread2 代码..
标签: c++ c multithreading gcc