1.什么是false sharing

在对称多处理器(SMP)系统中,每个处理器均有属于自己的本地高速缓存区。

如图,CPU0和CPU1有各自的本地高速缓存区(cache)。线程0和线程1会用到不同的变量,它们在内存中彼此相邻。内存以64字节分割高速缓存行,我们假设红色变量与蓝色变量恰好分配在同一条高速缓存行中。CPU如果想要读取变量,会以高速缓存行的形式加载到本地高速缓存区中。这个例子中,CPU0和CPU1加载了同一条高速缓存行。然后线程0修改了红色变量,线程1修改了蓝色变量,这导致了CPU1中红色变量不正常,CPU0中蓝色变量不正常,从而导致高速缓存行无效,并强制内存更新以维持高速缓存的一致性。

2.(intel)如何确保多个CPU中的高速缓存的数据一致性

Intel处理器遵循MESI协议(Modified/Exclusive/Shared/Invalid,修改/独占/共享/无效)。

独占:
首次加载高速缓存行时,处理器将高速缓存行标记为”独占”访问,一旦该高速缓存行被标记为独占,后续加载可以自由使用缓存中的现有数据。
共享:
如果该处理器看到相同的高速缓存行被其它处理器加载到总线上,就会将该高速缓存行标记为”共享”访问。
修改:
如果处理器修改并保存了”共享”的高速缓存行,该缓存行将被标记为”修改”,所有其它处理器会受到一条”无效”的信息。当处理器A看到其它处理器访问标记为”修改”的相同高速缓存,A会将该高速缓存行存回内存,并将其标记为”共享”,其它处理器丢失自己的对应的高速缓存行。
无效:
处理器之间频繁协调,将”修改”的高速缓存行写入内存,然后再加载

3.解决假共享的方法

所有方法的目的都是确保引起false sharing的变量在内存中存放的位置相隔足够远,从而不会驻留在同一个高速缓存行中。

方法1: 使用编译指令强制对齐单个变量。

使用__declspec (align(64))声明变量

例: 单个变量

__declspec (align(64)) int thread1_global_variable;
__declspec (align(64)) int thread2_global_variable;

例: struct

使用int padding[n]确保struct为64或64的倍数

struct ThreadParams
{
// For the following 4 variables: 4*4 = 16 bytes
unsigned long thread_id;
unsigned long v; // Frequent read/write access variable
unsigned long start;
unsigned long end; // expand to 64 bytes to avoid false-sharing
// (4 unsigned long variables + 12 padding)*4 = 64
int padding[12];
};
__declspec (align(64)) struct ThreadParams Array[10];
方法2:使用数据的线程本地拷贝来减少false sharing的频率
struct ThreadParams
{
// For the following 4 variables: 4*4 = 16 bytes
unsigned long thread_id;
unsigned long v; //Frequent read/write access variable
unsigned long start;
unsigned long end;
}; threadFunc(void *parameter)
{
ThreadParams *p = (ThreadParams*) parameter;
// local copy for read/write access variable
unsigned long local_v = p->v;
for(local_v = p->start; local_v < p->end; local_v++)
{
// Functional computation
}
p->v = local_v; // Update shared data structure only once
}

假设v在这个循环中每一次循环都被修改,那么,每一次修改都将触发false sharing。因此,我们使用线程本地变量local_v,所有的中间修改都在本地完成,仅在p->v = local_v;时更新数据结构

原文见:https://software.intel.com/zh-cn/articles/avoiding-and-identifying-false-sharing-among-threads

Linux -- 在多线程程序中避免False Sharing的更多相关文章

  1. zz剖析为什么在多核多线程程序中要慎用volatile关键字?

    [摘要]编译器保证volatile自己的读写有序,但由于optimization和多线程可以和非volatile读写interleave,也就是不原子,也就是没有用.C++11 supposed会支持 ...

  2. 多线程程序中fork导致的一些问题

    最近项目中,在使用多线程和多进程时,遇到了些问题. 问题描述:在多线程程序中fork出一个新进程,发现新的进程无法正常工作. 解决办法:将开线程的代码放在fork以后.也就是放在新的子进程中进行创建. ...

  3. Linux下多线程编程中信号量介绍及简单使用

    在Linux中有两种方法用于处理线程同步:信号量和互斥量. 线程的信号量是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作.如果一个程序中有多个线程试图改变一个信号量的值,系统将保 ...

  4. 为什么linux下多线程程序如此消耗虚拟内存【转】

    转自:http://blog.csdn.net/chen19870707/article/details/43202679 权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 探 ...

  5. CountDownLatch在多线程程序中的应用

    一.CountDownLatch介绍 CountDownLatch是JDK1.5之后引入的,存在于java.util.concurrent包下,能够使一个线程等待其他线程完成动作后再执行.构造方法: ...

  6. linux下Java程序中插入DB中国的数据乱码问题

    首先,插入到DB数据,在Linux在查询时,现场展示??. 再次,在windows连接到db上,查看的结果并非乱码. 改动Eclipse软件中的编码:如上图:windows菜单->prefere ...

  7. 如何在linux用户空间程序中打印时间戳?

    1. 使用clock_gettime接口即可 2. clock_gettime的使用方法: 2.1 定义一个结构体 struct timespec ts; 2.2 调用clock_gettime获取当 ...

  8. Linux 多线程应用中如何编写安全的信号处理函数

    http://blog.163.com/he_junwei/blog/static/1979376462014021105242552/ http://www.ibm.com/developerwor ...

  9. Linux 多线程应用中如何编写安全的信号处理函数【转】

    转自:https://www.cnblogs.com/virusolf/p/4945642.html http://blog.163.com/he_junwei/blog/static/1979376 ...

随机推荐

  1. Unable to open debugger port (127.0.0.1:63959): java.net.SocketException "socket closed",编译过来就是无法打开调试器端口,套接字已关闭

    最开始的预测: 这台笔记本操作系统是win10专业工作站版,debug启动项目,provide项目完美启动成功,然后consumer项目报错:Unable to open debugger port ...

  2. mysql双主模式方案

    MySQL双主(主主)架构方案   在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果 ...

  3. vue 安装 ‘node-sass’ 运行报错:ERROR in Cannot find module 'node-sass'

    好像是由于cnpm安装导致.执行下面的安装代码,或者使用npm 安装node-sass cnpm install node-sass@latest

  4. jquery轮播事件效果

    今天闲着有时间把轮播事件重新写了一下,发现以前用的很多插件大多支持度不算太友好,很多小问题 自己写了一个,不好地方请指教 先建立文件,css,js,图片,引入jquery <!DOCTYPE h ...

  5. mongodb中帮助信息和命令

    在Mongodb中,可以看作是一种面向对象的操作,如果你对与某一个操作不清楚,可以直接help. 在mongodb中,无非是对DB.user.collections.文档的操作. 下面是简单的示例: ...

  6. firewall 相关命令

    1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl disabl ...

  7. LOJ P10116 清点人数 题解

    每日一题 day13 打卡 Analysis 用简单的树状数组维护单点修改和查询就行了 #include<iostream> #include<cstdio> #include ...

  8. umediter实现粘贴word图片

    图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM ...

  9. 爬虫(九):scrapy框架回顾

    scrapy文档 一:安装scrapy a. pip3 install wheel b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#tw ...

  10. CF516D Drazil and Morning Exercise【并查集,结论】

    题目描述:一棵\(n\)个点的树,设\(d(u)=\max_{v\in V}\text{dis}(u,v)\),每次询问一个数\(l\),求一个最大的联通子图\(L\),使得\(\forall u,v ...