无锁代码下,在读写字段时使用内存屏障往往是不够的。在 64 位字段上进行加、减操作需要使用Interlocked工具类这样更加重型的方式。Interlocked也提供了ExchangeCompareExchange方法,后者能够进行无锁的读-改-写(read-modify-write)操作,只需要额外增加一点代码。

如果一条语句在底层处理器上被当作一个独立不可分割的指令,那么它本质上是原子的(atomic)。严格的原子性可以阻止任何抢占的可能。对于 32 位(或更低)的字段的简单读写总是原子的。而操作 64 位字段仅在 64 位运行时环境下是原子的,并且结合了多个读写操作的语句必然不是原子的:

class Atomicity
{
static int _x, _y;
static long _z; static void Test()
{
long myLocal;
_x = 3; // 原子的
_z = 3; // 32位环境下不是原子的(_z 是64位的)
myLocal = _z; // 32位环境下不是原子的(_z 是64位的)
_y += _x; // 不是原子的 (结合了读和写操作)
_x++; // 不是原子的 (结合了读和写操作)
}
}

在 32 位环境下读写 64 位字段不是原子的,因为它需要两条独立的指令:每条用于对应的 32 位内存地址。所以,如果线程 X 在读一个 64 位的值,同时线程 Y 更新它,那么线程 X 最终可能得到新旧两个值按位组合后的结果(一个撕裂读(torn read))。

编译器实现x++这种一元运算,是通过先读一个变量,然后计算,最后写回去的方式。考虑如下类:

class ThreadUnsafe
{
static int _x = 1000;
static void Go() { for (int i = 0; i < 100; i++) _x--; }
}

抛开内存屏障的事情,你可能会认为如果 10 个线程并发运行Go,最终_x会为0。然而,这并不一定,因为可能存在竞态条件(race condition),在一个线程完成读取x的当前值,减少值,把值写回这个过程之间,被另一个线程抢占(导致一个过期的值被写回)。

当然,可以通过用lock语句封装非原子的操作来解决这些问题。实际上,锁如果一致的使用,可以模拟原子性。然而,Interlocked类为这样简单的操作提供了一个更方便更快的方案:

class Program
{
static long _sum; static void Main()
{ // _sum
// 简单的自增/自减操作:
Interlocked.Increment (ref _sum); // 1
Interlocked.Decrement (ref _sum); // 0 // 加/减一个值:
Interlocked.Add (ref _sum, 3); // 3 // 读取64位字段:
Console.WriteLine (Interlocked.Read (ref _sum)); // 3 // 读取当前值并且写64位字段
// (打印 "3",并且将 _sum 更新为 10 )
Console.WriteLine (Interlocked.Exchange (ref _sum, 10)); // 10 // 仅当字段的当前值匹配特定的值(10)时才更新它:
Console.WriteLine (Interlocked.CompareExchange (ref _sum,
123, 10); // 123
}
}

Interlocked上的所有方法都使用全栅栏。因此,通过Interlocked访问字段不需要额外的栅栏,除非它们在程序其它地方没有通过Interlockedlock来访问。

Interlocked的数学运算操作仅限于IncrementDecrement以及Add。如果你希望进行乘法或其它计算,在无锁方式下可以使用CompareExchange方法(通常与自旋等待一起使用)。我们会在并行编程中提供一个例子。

Interlocked类通过将原子性的需求传达给操作系统和虚拟机来进行实现其功能。

Interlocked类的方法通常产生 10ns 的开销,是无竞争锁的一半。此外,因为它们不会导致阻塞,所以不会带来上下文切换的开销。然而,如果在循环中多次迭代使用Interlocked,就可能比在循环外使用一个锁的效率低(不过Interlocked可以实现更高的并发度)。

C# Interlocked 笔记的更多相关文章

  1. 读书笔记——Windows核心编程(8)Interlocked系列函数

    先让我们来复习下小学知识 A+B=C//式中A为被加数,B为加数. A-B=C//式中A为被减数,B为减数. 再让我们来明确一个知识点:返回值为void的Windows函数意味着一定会执行成功. -- ...

  2. 多线程笔记--原子操作Interlocked系列函数

    前面写了一个多线程报数的功能,为了描述方便和代码简洁起见,只输出最后的报数结果来观察程序运行结果.这非常类似一个网站的客户访问统计,每个用户登录用一个线程模拟,线程运行时将一个表示计数的变量递增.程序 ...

  3. InterLocked学习笔记

    在进行多线程编程的时候特别重要的一点就是多线程的同步,什么是同步呢?字面意思就是使多个不在同一线程执行的代码统一到一个线程中执行,但是对执行中的线程过程却无法控制,这就造成了多个线程可能同时操作同一个 ...

  4. 读书笔记——Windows核心编程(8)Interlocked单向链式栈

    SLists使用了无锁算法来保证原子同步,以提升系统性能,避免了诸如优先级挂和互锁的问题. 注意:所有的链表项必须对齐到MEMORY_ALLOCATION_ALIGNMENT.否则会出现奇葩的错误. ...

  5. 《learning hard C#学习笔记》读书笔记(19)多线程

    19.1 多线程编程知识 19.1.1 进程与线程的概念 进程: 可以理解为一块包含某些资源的内存区域,操作系统通过进程方式把它工作划分为不同的单元. 一个应用程序可以对应多个进程. 线程: 线程是进 ...

  6. CLR via C#学习笔记----知识总概括

    第1章 CLR的执行模型 托管模块的各个组成部分:PE32或PE32+头,CLR头,元数据,IL(中间语言)代码. 高级语言通常只公开了CLR的所有功能的一个子集.然而,IL汇编语言允许开发人员访问C ...

  7. 【CLR VIA C#】读书笔记

    工作几年了才看,记录下笔记备忘. 章节 笔记 1.CLR的执行模型 公共语言运行时(Common Language Runtime,CLR) 源代码-->编译器检查语法和分析源代码-->托 ...

  8. 《C#并行编程高级教程》第5章 协调数据结构 笔记

    本章介绍了一些轻量级的同步原语,其中有很大部分是.NET Framework 4才引入的. System.Threading.Barrier 用于一段程序分成多个阶段,每个阶段的开始都需要之前的阶段完 ...

  9. 《C#并行编程高级教程》第4章 并发集合 笔记

    这一章主要介绍了System.Collections.Concurrent下的几个类. ConcurrentQueue<T> 并发队列.完全无锁,使用CAS(compare-and-swa ...

随机推荐

  1. HTML <a> 标签

    一,定义和用法 所有浏览器都支持 <a> 标签. <a> 标签定义超链接,用于从一张页面链接到另一张页面. <a> 元素最重要的属性是 href 属性,它指示链接的 ...

  2. HTML <base> 标签 为页面上的所有链接规定默认地址或默认目标

    定义和用法 <base> 标签为页面上的所有链接规定默认地址或默认目标. 通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白. 使用 <base& ...

  3. 自定义JSP标签库及Properties使用

    自定义JSP标签库及Properties使用 自定义JSP标签 自定义JSP标签技术是在JSP 1.1版本中才出现的,它支持用户在JSP文件中自定义标签,这样可以使JSP代码更加简洁. 这些可重用的标 ...

  4. php服务器版本更新工具up2server

    为什么要做这个工具 之前做php 开发的时候,每次版本更新,要把修改的文件同步到服务器,都要小心翼翼,如果漏掉了文件,那就完蛋了,KPI,奖金什么的都没了. 所以写了这个工具.代码在github  h ...

  5. Linux内核--C语言中内嵌汇编 asm __volatile__

    在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可 ...

  6. Jquery分页功能

    Jquery代码 /// <reference path="jquery-1.9.1-vsdoc.js" />//锚点var anchor="#apage&q ...

  7. Jquery mobile 中在列表项上使用单选按钮

      无意中发现可以在li上实现开关按钮 http://jsfiddle.net/Gajotres/pzfr2/                 触类旁通,终于实现了在li上增加单选按钮组   @mod ...

  8. WPF学习之路(十二)控件(Range控件)

    ProgressBar 进度条,主要属性:Minimum\Maximun\Value, IsIndeterminate为True时,进度条会循环运转 <Grid> <Grid.Row ...

  9. 哭瞎!360云盘将关停,你的几十T照片和文件该怎么办

    IDO老徐刚得到了一个非常不开心的消息,360云盘将停止个人云盘服务...进行业务转型,在网盘存储.传播内容的合法性和安全性得到彻底解决之前不再考虑恢复,之后转型企业云服务. 而且之前共享的所有资料, ...

  10. maven 常见错误解决方法

    1. 最重要的一点,使用国内镜像,比如 oschina.net 的镜像: 搜 jar 推荐:http://maven.outofmemory.cn/,速度极快. 2. 错误:Could not res ...