Linux -- 在多线程程序中避免False Sharing
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的更多相关文章
- zz剖析为什么在多核多线程程序中要慎用volatile关键字?
[摘要]编译器保证volatile自己的读写有序,但由于optimization和多线程可以和非volatile读写interleave,也就是不原子,也就是没有用.C++11 supposed会支持 ...
- 多线程程序中fork导致的一些问题
最近项目中,在使用多线程和多进程时,遇到了些问题. 问题描述:在多线程程序中fork出一个新进程,发现新的进程无法正常工作. 解决办法:将开线程的代码放在fork以后.也就是放在新的子进程中进行创建. ...
- Linux下多线程编程中信号量介绍及简单使用
在Linux中有两种方法用于处理线程同步:信号量和互斥量. 线程的信号量是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作.如果一个程序中有多个线程试图改变一个信号量的值,系统将保 ...
- 为什么linux下多线程程序如此消耗虚拟内存【转】
转自:http://blog.csdn.net/chen19870707/article/details/43202679 权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 探 ...
- CountDownLatch在多线程程序中的应用
一.CountDownLatch介绍 CountDownLatch是JDK1.5之后引入的,存在于java.util.concurrent包下,能够使一个线程等待其他线程完成动作后再执行.构造方法: ...
- linux下Java程序中插入DB中国的数据乱码问题
首先,插入到DB数据,在Linux在查询时,现场展示??. 再次,在windows连接到db上,查看的结果并非乱码. 改动Eclipse软件中的编码:如上图:windows菜单->prefere ...
- 如何在linux用户空间程序中打印时间戳?
1. 使用clock_gettime接口即可 2. clock_gettime的使用方法: 2.1 定义一个结构体 struct timespec ts; 2.2 调用clock_gettime获取当 ...
- Linux 多线程应用中如何编写安全的信号处理函数
http://blog.163.com/he_junwei/blog/static/1979376462014021105242552/ http://www.ibm.com/developerwor ...
- Linux 多线程应用中如何编写安全的信号处理函数【转】
转自:https://www.cnblogs.com/virusolf/p/4945642.html http://blog.163.com/he_junwei/blog/static/1979376 ...
随机推荐
- Jmeter性能测试NoHttpResponseException (the target server failed to respond)
采用JMeter做Http性能测试时,在高并发请求的情况下,服务器端并无异常,但是Jmeter端报错NoHttpResponseException (the target server failed ...
- 2019-2020-1 20199301《Linux内核原理与分析》第一周作业
学习内容 搜查文件 刚添加的文件有时候会找不到 解决方案:新添加的文件要手动执行一次updatedb更新,就可以搜查到文件 查找某目录下的所有文件添加 * 号前面的反斜杠不能忘记打上,否则会无法找到 ...
- vue 传入一个对象的所有属性
- 多任务3(协程)--yield完成多任务交替执行
协程是并发,单线程,一次执行一个 来回切换 代码: import time def task_1(): while True: print("-----1-----") time. ...
- 洛谷P2577 午餐【贪心】【线性dp】
题目:https://www.luogu.org/problemnew/show/P2577 题意:n个人每个人有一个打饭时间和吃饭时间,将他们分成两个队伍.每个人打到饭之后就马上去吃饭.问怎么安排可 ...
- 使用JSP/Servalet技术开发新闻发布系统------JSP数据交互一
什么是内置对象 JSP内置对象是 Web 容器创建的一组对象,不用通过手动new就可以使用 JSP中的九大内存对象 request 请求对象 response 响应对象 out 输出对象 ...
- Java知识点汇总-1
目录 1 native方法 2 泛型 3 hashcode 4 JDK主要的包 5 被final修饰的类特点 6 空串与null串 7 判断字符串是否相等 1 native方法 JDK源代码由C++. ...
- /dev/null和/dev/zero的作用
经常会看到dd命令用到/dev/zero文件,这里总结一下/dev/null和/dev/zero的作用和使用实例. 在类Unix系统(包括Linux)中,/dev/null 它是空设备,也称为位桶(b ...
- 51nod 3 * problem
1640题意:一张无向图在最小化最大边后求最大边权和 Slove:sort 最小生成树倒叙最大生成树 #include <iostream> #include <cstdio> ...
- P2701 [USACO5.3]巨大的牛棚Big Barn
题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...