Xeon上如何在不同核之间同步数据(linux如何使用内存屏障)

Posted

技术标签:

【中文标题】Xeon上如何在不同核之间同步数据(linux如何使用内存屏障)【英文标题】:How Can synchronize data between differernt cores on Xeon (linux how to use memory barriers) 【发布时间】:2013-12-31 13:38:22 【问题描述】:

我写了一个简单的程序来测试内存同步。使用全局队列与两个共享 进程,并将两个进程绑定到不同的核心。我的代码被炸毁了。

 #include<stdio.h>
 #include<sched.h>
 #define __USE_GNU

 void bindcpu(int pid) 
     int cpuid;
     cpu_set_t mask;
     cpu_set_t get;
     CPU_ZERO(&mask);

     if (pid > 0) 
         cpuid = 1;
      else 
         cpuid = 5;
     

     CPU_SET(cpuid, &mask);

     if (sched_setaffinity(0, sizeof(mask), &mask) == -1) 
         printf("warning: could not set CPU affinity, continuing...\n");
     
 

 #define Q_LENGTH 512
 int g_queue[512];

 struct point 
     int volatile w;
     int volatile r;
 ;  

 volatile struct point g_p;


 void iwrite(int x) 
     while (g_p.r == g_p.w);
     sleep(0.1);
     g_queue[g_p.w] = x;
     g_p.w = (g_p.w + 1) % Q_LENGTH;
     printf("#%d!%d", g_p.w, g_p.r);
 

 void iread(int *x) 
     while (((g_p.r + 1) % Q_LENGTH) == g_p.w);
     *x = g_queue[g_p.r];
     g_p.r = (g_p.r + 1) % Q_LENGTH;
     printf("-%d*%d", g_p.r, g_p.w);
 

 int main(int argc, char * argv[]) 
     //int num = sysconf(_SC_NPROCESSORS_CONF);
     int pid;

     pid = fork();
     g_p.r = Q_LENGTH;
     bindcpu(pid);
     int i = 0, j = 0;

     if (pid > 0) 
         printf("call iwrite \0");
         while (1) 
             iread(&j);
         
      else 
         printf("call iread\0");
         while (1) 
             iwrite(i);
             i++;
         
     

 

两个进程Intel(R) Xeon(R) CPU E3-1230和两个核心之间的数据不同步。

CPU:Intel(R) Xeon(R) CPU E3-1230 操作系统:3.8.0-35-generic #50~precise1-Ubuntu SMP

我想知道 IPC 之外的我如何在用户的不同内核之间同步数据 空间?

【问题讨论】:

如果您希望两个进程能够相互通信,您将需要使用某种形式的进程间通信。这里有一个关于进程间通信的好答案 -> ***.com/questions/2682462/c-fork-and-sharing-memory。另外,只是一个观察,你没有初始化你的点结构实例。 全局初始化默认为0。谢谢你的链接。 我想知道 IPC 之外的东西,是一种从用户空间控制缓存内存的方法。或任何系统调用,如“rmb()、wmb()” 【参考方案1】:

如果您希望您的应用程序操纵 cpus 共享缓存以完成 IPC,我认为您无法做到。

《Linux Kernel Development Second Edition》第 9 章有关于同步多线程应用程序的信息(包括原子操作、半量、屏障等...): http://www.makelinux.net/books/lkd2/ch09

所以你可能会得到一些关于你在那里寻找什么的想法。

这里是英特尔® 智能缓存“共享缓存多核系统的软件技术”的一篇不错的文章:http://archive.is/hm0y

这里有一些 *** 问题/答案可以帮助您找到您正在寻找的信息:

Storing C/C++ variables in processor cache instead of system memory

C++: Working with the CPU cache

Understanding how the CPU decides what gets loaded into cache memory

很抱歉用链接轰炸你,但如果没有更清楚地了解你想要完成的事情,这是我能做的最好的事情。

【讨论】:

谢谢!是我的问题是我没有明确我想知道的。 我阅读了这个链接,我认为共享的 chache 很酷,而且它是starmt。我的 cpu 得到了 L3 可以共享,但它没有工作。如何检查系统上的缓存配置,如何修改?【参考方案2】:

我建议阅读“Volatile: Almost Useless for Multi-Threaded Programming”,了解为什么应从示例代码中删除 volatile。相反,使用 C11 或 C++11 原子操作。另请参阅 TBB 设计模式手册中的 Fenced Data Transfer 示例。

下面我展示了我更改为使用 C++11 原子的问题示例的部分内容。我用 g++ 4.7.2 编译它。

 #include <atomic>

...

  struct point g_p;

  struct point 
      std::atomic<int> w;
      std::atomic<int> r;
  ;

 void iwrite(int x) 
     int w = g_p.w.load(std::memory_order_relaxed);
     int r;
     while ((r=g_p.r.load(std::memory_order_acquire)) == w);
     sleep(0.1);
     g_queue[w] = x;
     w = (w+1)%Q_LENGTH;
     g_p.w.store( w, std::memory_order_release);
     printf("#%d!%d", w, r);
 

 void iread(int *x) 
     int r = g_p.r.load(std::memory_order_relaxed);
     int w;
     while (((r + 1) % Q_LENGTH) == (w=g_p.w.load(std::memory_order_acquire)));
     *x = g_queue[r];
     g_p.r.store( (r + 1) % Q_LENGTH, std::memory_order_release );
     printf("-%d*%d", r, w);
 

主要变化是:

我到处都删除了“volatile”。 struct point 的成员被声明为 std::atomic g_p.r 和 g_p.w 的一些加载和存储被隔离。其他人被吊起。 加载由另一个线程修改的变量时,代码会将其“快照”到局部变量中。

代码使用“松弛加载”(无栅栏),其中线程加载没有其他线程修改的变量。我将这些负载从旋转循环中取出,因为重复它们没有意义。

代码使用“获取负载”,其中线程加载由另一个线程设置的“消息准备就绪”指示器,并使用“释放存储”存储“消息准备就绪”指示器“以供读取由另一个线程。释放是确保“消息”(队列数据)写入之前写入“就绪”指示符(g_p 的成员)所必需的。获取同样需要确保在看到“就绪”指示器之后读取“消息”。

使用快照以便 printf 报告线程实际使用的值,而不是稍后出现的一些新值。一般来说,我喜欢使用快照风格有两个原因。首先,接触共享内存可能会很昂贵,因为它通常需要高速缓存行传输。其次,该样式为我提供了一个稳定的值,可以在本地使用,而不必担心重新读取可能会返回不同的值。

【讨论】:

我发现我的代码有错误,我认为 fork 会让进程共享相同的 mm_struct 这意味着 porcesses 正在运行内存空间,但我检查了内核代码,从 fork 进程中内存是“写入时复制”,因此每个进程在自己的内存空间中都有自己的副本(通过页面错误实现)。 并且使用 vfork 和 memory barriy 可以完成我想要的。我想尽可能快地运行代码,多核可以,一个生产,消费,没有任何 IPC,没有任何 atmic,没有任何管道中断,并尽可能高地命中缓存。

以上是关于Xeon上如何在不同核之间同步数据(linux如何使用内存屏障)的主要内容,如果未能解决你的问题,请参考以下文章

如何在所有 iDevices 之间同步数据 [关闭]

数据库与数据库之间数据如何同步

如何在linux中同步套接字服务器和客户端之间的通信速率

两台数据库服务器 如何进行数据同步操作

技术干货|如何利用 ChunJun 实现数据离线同步?

菜菜的sklearn课堂笔记支持向量机-探索核函数在不同数据集上的表现