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 ...
随机推荐
- 牛客练习赛50 D tokitsukaze and Event (最短路,思维)
牛客练习赛50 D tokitsukaze and Event 链接:https://ac.nowcoder.com/acm/contest/1080/D来源:牛客网 时间限制:C/C++ 1秒,其他 ...
- k8s的监控
监控 1.资源指标和资源监控 一个集群系统管理离不开监控,同样的Kubernetes也需要根据数据指标来采集相关数据,从而完成对集群系统的监控状况进行监测.这些指标总体上分为两个组成:监控集群本身和监 ...
- JDK源码那些事儿之PriorityBlockingQueue
今天继续说一说阻塞队列的实现,今天的主角就是优先级阻塞队列PriorityBlockingQueue,从命名上看觉得应该是有序的,毕竟是优先级队列,那么实际上是什么情况,我们一起看下其内部实现,提前说 ...
- Android 测试-Robolectric,mockito,esspresso
代码参考:https://github.com/googlesamples/android-testing 解释参考: https://www.jianshu.com/p/5732b4afd12f 官 ...
- 聊聊Hash索引
hash index是基于哈希表实现的,只有精确匹配索引所有列的查询才会生效.对于每一行数据,存储引擎都会对所有的索引列计算一个hash code,并将的有的hash code存储在索引中,同时在哈希 ...
- python+request 常用基础学习笔记
1.pycharm,避免控制台输出的json内容中文出现乱码. #注:乱码为Unicode格式:\u6d4b\u8bd5.加入如下代码后正确返回中文:测试 get_result = r.json() ...
- 并发编程大师系列之:线程的定义和中断 interrupt
1.启动线程的三种方式: 1.1继承Thread类 public static class UseThread extends Thread { public void run() { System. ...
- Jfinal undertow本地运行加载静态文件
undertow部署文档中可配置静态资源也可以添加磁盘目录作为项目中得静态文件访问 undertow.resourcePath = src/main/webapp, D:/static 这样配置就可以 ...
- 第十三章 使用ADO.NET访问数据库
一,什么是ADO.NET ADO.NET 是一种以面向对象的设计方法构建的数据访问和操作的类库,它建立在.NET平台上,以便于操作各种各样的数据源.这些数据源可以是数据库, 也可以是文本文件 ,EXC ...
- Greenplum table 之 appendonly表
一.压缩表 1.appendonly压缩表的数据视图为pg_appendonly 2.appendonly在Greenplum后也可更新与删除