Interlocked系列函数可以对内存进行原子操作,它是如何实现的?
    它的实现依赖于底层的CPU架构。对于某些CPU来说,这很简单,例如x86可以通过LOCK前缀直接支持Interlocked操作(有一个额外的特性就是XCHG指令总是隐式包含了LOCK前缀)。IA64和x64也直接支持原子的load-modify-store操作。
    其它的多数CPU架构把这个操作分成两部分,被称为Load-link/store-conditional。第一部分(load-link)从指定内存地址读取一个值,并且处理器会监视这个内存地址,看是否有其它处理器修改该值。第二部分(store-conditional)是如果这期间没有其它处理器修改该值,则将新值存回该地址。因此,一个原子的load-link/store-conditional操作就是通过load-link读取值,进行一些计算,然后试图store-conditional。如果store-conditional失败,那么重新开始整个操作。
 LONG InterlockedIncrement( LONG volatile *value )
{
LONG lOriginal, lNewValue;
do
{
//
//通过load-link读取当前值
//可以知道写回之前是否有人修改它
//
lOriginal = load_link(value); //
//计算新的值
//
lNewValue = lOriginal + ; //
//有条件的写回新值
//如果有人在计算期间覆写该值,则函数返回失败
//
} while ( !store_conditional(value, lNewValue));
return lNewValue;
}
(如果看起来有些熟悉,是的,你之前见到过这种模式。)
    请求CPU监视一个内存地址依赖于CPU自己的实现。但要记住一件事情,CPU在同一时间只能监视一个内存地址,并且这个时间是很短暂的。如果你的代码被抢占了或者在load-link后有一个硬件中断到来,那么你的store-conditional将会失败,因为CPU因为硬件中断而分心了,完全忘记了你要求它监视的内存地址(即使CPU成功的记住了它,也不会记太久,因为硬件中断几乎都会执行自己的load-link指令,因此会替换成它自己要求监视的内存地址)。
    另外,CPU可能会有点懒,在监视时并不监视内存地址,而是监视cache line,如果有人修改了一个不同的内存位置,但是刚好跟要被监视的内存地址在同一个cache line里,store-conditional操作也会失败,即使它事实上可以成功完成。ARM架构的CPU是太懒了,以至于任何向同一块2048字节写入的操作都会导致store-conditional失败。
    这对于需要用汇编语言来实现Interlocked操作的你来说意味着什么?你需要尽可能减少load-link和store-conditional之间的指令数。例如,InterlockedIncrement只不过是给值加1。你在load-link和store-conditional之间插入的指令越多,store-conditional失败的可能就越大,你就不得不重来一次。如果你在两者之间插入的指令太多了就会导致store-conditional永远不会成功。举一个极端的例子,如果你计算新值的代码需要耗时5秒,在这5秒内肯定会接收到很多硬件中断,store-conditional操作就永远都会失败。
 
本文译自The Old New Thing,原文地址http://blogs.msdn.com/b/oldnewthing/archive/2013/09/13/10448736.aspx

最新文章

  1. The Skins of the Substance
  2. 超简单的处理JSON格式和JSON数组格式的String
  3. 对象的类型转换P109
  4. MORE ABORT AWR?
  5. android jni (5)——Field & Method --> Accessing Mehtod
  6. Monkey源代码分析番外篇WindowManager如何出的喷射事件的进程间的安全限制
  7. Spring MVC中的HandlerMapping与HandlerAdapter
  8. 【转】Spring AOP 实现之CGLIB
  9. [csdn markdown]使用摘记三 简便快捷的流程图
  10. 学习Xen
  11. SpringCloud Hystrix熔断之线程池
  12. tomcat服务器怎样远程调试
  13. A1123. Is It a Complete AVL Tree
  14. word2vec skip-gram系列2
  15. Python 进程之间共享数据
  16. Mysqldump备份说明及数据库备份脚本分享-运维笔记
  17. Spring MVC注解配置
  18. PHP中session_start 函数详解使用方法
  19. java-类与类,类与接口,接口与接口的关系
  20. Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)

热门文章

  1. JMeter学习笔记(二) 一些实际应用的基础操作
  2. python序列和其它类型的比较
  3. 运输层(TCP/UDP)详解
  4. ObjectAnimator实现菜单的弹出(扇形)
  5. JQuery点击打开再点击关闭
  6. C++数字三角形问题与dp算法
  7. DruidDataSource源码分析
  8. 如何更改Arcmap里经纬度小数点后面的位数?
  9. GitHub 的简单使用
  10. "Hello World"团队召开的第三周第七次会议