关于.net中线程原子性的自我总结

首先来张图,一张 cpu的简图,仅从个人理解角度理解画的

 关于.net中线程原子性的自我总结_第1张图片

  大体 解释下这张图 这是 一张 i5的简图i5 大家都知道 是双核四线程,(超线程技术)l1,l2,l3是 1,2,3级缓存。

 

  Cpu工作:每次计算任务 cpu 都去找l1,如果l1没有就去找l2,依次查找,然后依次将数据从内存加载l3,l2,l1 然后加载到 寄存器操作。

 

  现在引入 一个问题 a+=1; 怎么执行的

  首先 a+=1 是 分成 以下几部执行的

  1. 内存中找到a
  2. 在寄存器中 a+1
  3. 把结果写回内存中

 

  对应的 汇编代码 不写了→_→(我忘了)

  

  问题: 如果 a=0,2个线程 同时执行这端代码,结果是1还是 2呢?

  看图 那么如果 核心1 和 核心2 同时 执行这段 代码(也就是 2个线程 同时执行)会发生什么………

 

假设1:当线程1 执行到 读取a 时,线程2 也读取a的值,当线程1执行+1时,线程2也同操作,最后结果显而易见 是1 (当然 cpu 不会让这件事件发生。因为 他有Cache Coherence处理)

假设2:当线程1执行完后,线程2在执行 结果就是2了。。

 

再举一个例子:

 

经典的 单例模式:(双检索)

 

 1 If(xxx==null 2 
 3 {
 4 
 5          Lock(“我是打酱油的”)
 6 
 7    {
 8 
 9            If(xxx==null)
10 
11      {
12 
13              xxx=new xxxxx();
14 
15       }
16 
17     }
18 
19 }

 

 

  大家都知道这个是线程安全的,但是 这种只是减少不安全的几率

  分析一下:

  这段代码执行的过程

 

  1、  创建对象

  2、  将对象的地址赋值给xxx

 

在即时编译器 是乱序执行的,调用分配内存和调用构造函数不是一个原子操作,可能导致先执行2,在执行1,那么就报错了

 

此例子来源 CLR via C#这本书,如果想详细了解请看这本书。

 

当然这个话题是想引起 对 ”原子性” 讨论 。

 

其实,每次我看到 原子性 都想到 线程锁,线程串行化等

 

当然这种 线程安全问题 利用锁(lock关键字) 是一种很好的 解决方案,有没有 更有效地解决方法呢?

 

答案是 System.Threading.Interlocked这个类

相关的信息:http://www.cnblogs.com/mgen/archive/2013/05/27/3101755.html#_h2

 

当然这个类的底层是 实现的呢 ,是这对方法: Thread.VolatileRead 和Thread.VolatileWrite

 

原理:是要求cpu 每次计算完后 都直接 写入内存 ,也就不存在文章开头存在问题。

 

 最后 感谢 宝生兄的讲解 http://www.cnblogs.com/francisYoung/

 

最后推荐 一个大神的 博客 http://www.parallellabs.com

 

你可能感兴趣的:(.net)