多线程,使用全局变量比使用全局指针慢了一倍,为什么?
我有下面一个这样的测试程序:#include<pthread.h>
#include<stdlib.h>
struct M{
long a;
long b;
}obj;
size_t count=2000000000;
void* addx(void*args){
long*pl=(long*)args;
for(size_t i=0;i<count;++i)
(*pl)*=i;
return NULL;
}
int main(int argc,char*argv[]){
pthread_t tid;
pthread_create(&tid,NULL,addx,&obj.a);
pthread_create(&tid,NULL,addx,&obj.b);
pthread_join(tid,NULL);
pthread_join(tid,NULL);
return 0;
}
用clang来测试,注意已经加了-O2优化选项:
clang++ test03_threads.cpp -o test03_threads -lpthread -O2 && time ./test03_threads
real 0m3.626s
user 0m6.595s
sys 0m0.009s
看起来挺慢的,我把全局obj改成*obj,运行时创建。我期待这个会更慢一点:
#include<pthread.h>
#include<stdlib.h>
struct M{
long a;
long b;
}*obj;
size_t count=2000000000;
void* addx(void*args){
long*pl=(long*)args;
for(size_t i=0;i<count;++i)
(*pl)*=i;
return NULL;
}
int main(int argc,char*argv[]){
obj=new M;
pthread_t tid;
pthread_create(&tid,NULL,addx,&obj->a);
pthread_create(&tid,NULL,addx,&obj->b);
pthread_join(tid,NULL);
pthread_join(tid,NULL);
delete obj;
return 0;
}
但是出乎我的意料,变快了:
clang++ test03_threads_new.cpp -o test03_threads_new -lpthread -O2 && time ./test03_threads_new
real 0m1.880s
user 0m3.745s
sys 0m0.007s
而且快了差不多100%。我用linux+gcc测试了一下,一样的结果。
这到底是什么,什么原因造成了这么大的性能差异?
本帖最后由 xinglp 于 2017-04-23 09:09 编辑
gcc 6.3.0
glibc 2.25
双核环境
-O2 -O3 以及不加 没有任何差异
我猜测可能是 false_sharing 造成的, 后一种方法虽然慢, 但是更多的代码, 就减少了冲突的发生. 本帖最后由 lxyscls 于 2017-05-09 09:24 编辑
回复 1# cdsfiui
long a 和 long b之间不存在"伪共享",因为会被优化到寄存器里面去
struct m和int count间存在"伪共享"
回复 3# wlmqgzm
更多的代码就能减少冲突的发生吗?
for(size_t i=0;i<count;++i)
第一个方法方法, count 和struct M再同一个cache line。
每次判断count的时候都要读内存,由于两个core在不断修改该内存。所以这里较大概率发生cache miss。 (invalid -> shared状态)
http://blog.csdn.net/muxiqingyang/article/details/6615199
I(Invalid)
Local Read
如果其它Cache没有这份数据,本Cache从内存中取数据,Cache line状态变成E;
如果其它Cache有这份数据,且状态为M,则将数据更新到内存,本Cache再从内存中取数据,2个Cache 的Cache line状态都变成S;
如果其它Cache有这份数据,且状态为S或者E,本Cache从内存中取数据,这些Cache 的Cache line状态都变成
解决方法:
1. 结构体增加__cacheline_aligned对齐属性。
2. count写死成常数。
页:
[1]