lockfree
为什么要lockfree
按我的理解, lockfree就是不去 调用操作系统给定的锁机制.
1. 会有system call, and system call is expensive; 比如pthread在linux里调用了futex.
2. 会失去控制, 接下来发生什么看操作系统心情了.
怎么做lockfree
不用操作系统给定的 同步机制, 而使用 硬件提供的机制, 简单说, 就是对 机器指令 的封装函数(right?).
首先一个是 compare-and-set. CAS/TAS
保证对某个变量的读出和修改是 原子的. 如下:
typedef LONG volatile tsl_t; #define MUTEX_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1))
#define MUTEX_UNSET(tsl) InterlockedExchange((PLONG)tsl, 0)
`MUTEX_SET`返回1 表示已经锁住:
若此时 `tsl`为1, 表示已经被锁了, 置`tsl`为1, 返回原值的!, 即为0;
若此时 `tsl`为0, 表示锁可用, 置`tsl`为1, 返回1, 成功.
`MUTEX_SET`会被放入一个 loop中不断重试. 在gcc中, 可以用类似 `__sync_bool_compare_and_swap`的原语:
https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html
对应不同的硬件/编译器, 可以使用的cas不同. 例子: bdb: mutex_int.h. wiredtiger: gcc.h/msvc.h
memory barrier解决乱序
出于性能考虑, 编译器/硬件 会 reorder execution of your program. 对单线程程序 完全没有影响, 多线程就不行了.
编译器会reorder: 这个算内部矛盾? 毕竟都是软件的事
硬件(cpu) 会reorder: 对cpu来说, 数据放在三个地方: 寄存器/cpu缓存/主存.
LOAD - 从主存读入 到寄存器/缓存
STORE - 从寄存器/缓存 写入主存
本来 有 MESI - 缓存一致性协议(cache coherency) 保证 缓存-主存的一致性的:
https://en.wikipedia.org/wiki/MESI_protocol
modified - exclusive - shared - invalid
MESI是一个理论上的东西. 在实现上, 从性能考虑, 加入 store buffers, invalidate queues.
store buffer:
要解决的问题: 写一个shared/invalid cache line, 先广播 read-invalid message, 让别的处理器都invalid, 返回Invalidate Acknowledge, 然后才能写入cache.
解决方案:可以写入store buffer, 广播, 当前processor 接着做别的. 等收到所有处理器都invalid完了, 返回Invalidate Acknowledge, , 在写入cache. (异步执行的意思?)
给程序带来的新问题: write离开 buffer的时间 和 异步执行有关. 和程序原order无关.
invalidate queue:
要解决的问题: invalid 一个cache line挺慢的; 万一store buffer满了, processor 需要等待 某write释放 才能继续.
解决方案: 把 invalid 请求 入queue, 立即发送Invalidate Acknowledge, 然后慢慢执行queue. (还是异步?)
给程序带来的新问题:
Memory Barrier:
A store barrier will flush the store buffer, ensuring all writes have been applied to that CPU's cache.
A read barrier will flush the invalidation queue, thus ensuring that all writes by other CPUs become visible to the flushing CPU.
在做下一次store前, 保证store buffer被处理完 - membar之前的写 全部在cache里;
在做下一次load前, 保证invalidation queue被处理完 - 保证cache中没有过期数据.
full membar
read membar: flush invalidation queue
write member: flush store buffer
LFENCE/SFENCE/MFENCE
acquire/release
LoadLoad/LoadStore/StoreLoad/StoreStore: sparc
volatile: 对c来说, 用于阻止编译器过度优化. 如 替换 循环变量为 `while(true)` -- (这个我见过!); 改内存访问为 寄存器访问等.
http://lwn.net/Articles/250967/
http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_11
http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf
lockfree的更多相关文章
- Lock-Free 编程
文章索引 Lock-Free 编程是什么? Lock-Free 编程技术 读改写原子操作(Atomic Read-Modify-Write Operations) Compare-And-Swap 循 ...
- Lock,LockFree,MemoryBarrier,ConcurrentCollection
最近看并行编程书本的一些心得,简单记录下多线程和并行编程必知必会的几个概念,再次加深自己的理解. .NET Framework4提供了一个新的命名空间System.Collections.Concur ...
- 无锁数据结构(Lock-Free Data Structures)
一个星期前,我写了关于SQL Server里闩锁(Latches)和自旋锁(Spinlocks)的文章.2个同步原语(synchronization primitives)是用来保护SQL Serve ...
- 使用C++11实现无锁stack(lock-free stack)
前几篇文章,我们讨论了如何使用mutex保护数据及使用使用condition variable在多线程中进行同步.然而,使用mutex将会导致一下问题: 等待互斥锁会消耗宝贵的时间 — 有时候是很多时 ...
- Boost Lockfree
Boost Lockfree flyfish 2014-9-30 为了最大限度的挖掘并行编程的性能考虑使用与锁无关的数据结构来编程 与锁无关的数据结构不是依赖于锁和相互排斥来确保线程安全. Lockf ...
- 并发编程(三): 使用C++11实现无锁stack(lock-free stack)
前几篇文章,我们讨论了如何使用mutex保护数据及使用使用condition variable在多线程中进行同步.然而,使用mutex将会导致一下问题: 等待互斥锁会消耗宝贵的时间 - 有时候是很多时 ...
- boost::lockfree::queue多线程读写实例
最近的任务是写一个多线程的东西,就得接触多线程队列了,我反正是没学过分布式的,代码全凭感觉写出来的,不过运气好,代码能够work= = 话不多说,直接给代码吧,一个多消费者,多生产者的模式.假设我的任 ...
- 【Java并发编程】2、无锁编程:lock-free原理;CAS;ABA问题
转自:http://blog.csdn.net/kangroger/article/details/47867269 定义 无锁编程是指在不使用锁的情况下,在多线程环境下实现多变量的同步.即在没有线程 ...
- 读Lock-Free论文实践
论文地址:implementing Lock-Free Queue 论文大体讲的意思是:Lock-Base的程序的performance不好,并且a process inside the critic ...
随机推荐
- Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute'
[TypeLoadException: Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from as ...
- array_filter,匿名函数
static function get_categoryII() { return array( array('id' => 1, 'c1id' => 1, 'name' => '1 ...
- GTD
这两天坚持GTD,四分象限法管理时间,感觉学习专注度明显提升,一直没完成的马士兵JAVA基础整到第八章了,继续保持,1.13号前争取11章全整完. 3个点支撑起你的职业发展:技术,管理(管理自己.管理 ...
- Struts框架——(二)Struts原理with登录实例
二. Struts基本工作流程 假设现在有以下情景: 用户正在浏览一个用STRUTS的技术构建的网站主页,主页上有个登陆表单,用户填好登陆名和密码,单击"登陆"按钮,就激活了以下一 ...
- Oracle分页存储过程
1.在oracle的sqlplus或其他工具中运行一下pl/sql块建立存储过程 --创建包create or replace package testpackage astype test_curs ...
- 接入百度语音SDK的步骤
1.导入依赖库 SystemConfiguration.framework AudioToolbox.framework UIkit.framework AVFoundation.framework ...
- js+cookie 购物车
$(function () { //var ctx = new Ch(); //ctx.Clear(); //$.cookie(ctx.cookieName, ""); //ale ...
- Daily Scrum 12.17
今日完成任务: 解决匿名回答时候字数限制问题:完善了用户界面的UI设计: 明日任务: 孙思权 接口设计 晏旭瑞 资源索引问题 冯飘飘 解决上传资源时候不勾选或不添加选项内容可以上传的问题 黎柱金 进行 ...
- [转]Snappy压缩库安装和使用之一
Snappy压缩库安装和使用之一 原文地址:http://blog.csdn.net/luo6620378xu/article/details/8521223 近日需要在毕业设计中引入一个压缩库,要求 ...
- GIL与线程互斥锁
GIL 是解释器级别的锁,是限制只有一个原生线程运行,防止多个原生线程之间修改底层的共享数据.而线程互斥锁是防止多个线程同时修改python内存空间的共享数据.