使用pthread时,使用全局变量的C++显示比指针慢100%?

Tro*_*yvs 6 c++ linux variables performance pthreads

我有一个很好的程序来显示2个类似程序的性能,它们都使用2个线程来进行计算.核心区别在于,一个使用全局变量,另一个使用"新"对象,如下所示:

#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[2];
    pthread_create(&tid[0],NULL,addx,&obj.a);
    pthread_create(&tid[1],NULL,addx,&obj.b);
    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
    return 0;
}

clang++ test03_threads.cpp -o test03_threads -lpthread -O2 && time ./test03_threads

real    0m3.626s
user    0m6.595s
sys 0m0.009s
Run Code Online (Sandbox Code Playgroud)

它很慢,然后我修改了obj以动态创建(我预计它会更慢):

#include<pthread.h>
#include<stdlib.h>
struct M{
    long a;
    long b;
}*obj;//difference 1
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;//difference 2
    pthread_t tid[2];
    pthread_create(&tid[0],NULL,addx,&obj->a);//difference 3
    pthread_create(&tid[1],NULL,addx,&obj->b);//difference 4
    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
    delete obj;//difference 5
    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
Run Code Online (Sandbox Code Playgroud)

它比前一个快100%.我也试过linux上的g ++,结果相同.但是如何解释呢?我知道obj是全局变量,但是*obj仍然是全局变量,只是动态创建的.核心区别是什么?

gez*_*eza 3

我认为这确实是因为错误共享,正如 Unimportant 所建议的那样。

您可能会问,为什么会有这种差异?

因为变数count!由于这是一个变量,并且size_t的基础类型恰好适合long您,因此编译器无法优化它(因为pl可以指向count)。如果countint,由于严格的别名规则,编译器可以将其优化掉(或者简单地可以是const size_t)。

所以生成的代码每次都必须count在循环中读取。

在第一个示例中,count两个obj全局变量都放置在彼此附近。因此,链接器很有可能将这些变量放入同一缓存行中。因此写入obj.aorobj.b将使 的缓存行无效count所以CPU必须同步读取count

在第二个示例中,obj被分配在堆上,它的地址将离 足够远count,因此它们不会占用相同的缓存行。无需同步count