当前位置: 代码迷 >> 综合 >> 多线程伪共享(false sharing)问题分析
  详细解决方案

多线程伪共享(false sharing)问题分析

热度:31   发布时间:2023-12-12 05:31:31.0

在多核的CPU架构中,每一个核心core都会有自己的缓存空间,因此如果一个变量如果同时存在不同的核心缓存空间时,就会出现伪共享(false sharing)的问题。

此时如果一个核心修改了该变量,该修改需要同步到其它核心的缓存。


在linux执行cat /proc/cpuinfo 来查看cpu的缓存的行大小:

cache_alignment : 64,

在目前的Intel处理器中cache是64B对齐的,因此K * 64与(K + 1) * 64 - 1的内存块在同一cache行中。


查看下面一段代码

#include<stdio.h> 
#include<omp.h> 
#include<string.h> 
#include<time.h> 
#include<stdlib.h> 
#include<iostream> 
using namespace std; #define NMAX 4096 * 10 
#define NUM_CORE 4 int g_iBuff[NMAX]; int main() 
{ int alignPos = 0; for (int i = 0; i < 65; ++i) {   if (((int)&g_iBuff[i]) % 64 == 0) {   alignPos = i; break; }   }   for (int pos = 1; pos <= 4096; pos <<= 1) {   memset(g_iBuff, 0 , sizeof(g_iBuff)); time_t beg = time(0); 
#pragma omp parallel for num_threads(NUM_CORE) for (int i = 0; i < NUM_CORE; ++i) {   int tp = i * pos + alignPos; for (int j = 0; j < 999999999; ++j) {   g_iBuff[tp]++; }   }   time_t end = time(0); cout << "false shareing: step = "<<pos<<" time = "<< end - beg << "s" <<endl; }   return 0; 
}

# g++ XX.cpp -o xx -fopenmp

# ./xx 

我们首先来看一下这段代码的输出结果:

false shareing: step = 1 time = 12s
false shareing: step = 2 time = 13s
false shareing: step = 4 time = 13s
false shareing: step = 8 time = 6s
false shareing: step = 16 time = 3s
false shareing: step = 32 time = 3s
false shareing: step = 64 time = 3s
false shareing: step = 128 time = 3s
false shareing: step = 256 time = 3s
false shareing: step = 512 time = 3s
false shareing: step = 1024 time = 3s
false shareing: step = 2048 time = 3s
false shareing: step = 4096 time = 3s


接下来我们来分析一个程序:


    for (int i = 0; i < 65; ++i) {   if (((int)&g_iBuff[i]) % 64 == 0) {   alignPos = i; break; }   } 
上面这段代码的功能是找到地址是64倍数的内存位置, alignPos;

r接下来我们在4核的机器来来验证伪共享对程序的影响。

当 step = 1时,4个线程写入的位置(相对alignPos开始位置)0,4,8和12,显然存在伪共享。

当 step = 2时,写入的位置分别为0,8,16和24,同样也是伪共享

当 step = 4时,写入的位置分别为0,16,32和48,同样也是伪共享

当 step = 8时,写入的位置分别为0,32,64和96,由于cache是64B对齐,因此,0和32以及64和96存在伪共享,但是比前3种情况要好。

对 step = 16时,写的位置分别为0,64,128,和192,刚好完全不再具有伪共享的问题。

step > 16, 也不会再存在伪共享。


这样我们就可以解释上程序在不同step上的执行时间问题。

  相关解决方案