概念

原子操作(atomic action):也叫primitive(原语、基元),它是操作系统用语范畴。指由若干条指令组成的,用于完成一定功能的一个过程。  原语是由若干个机器指令构成的完成某种特定功能的一段程序,具有不可分割性·即原语的执行必须是连续的,在执行过程中不允许被中断。

操作系统只需在执行以下操作时暂时屏蔽全部中断:测试信号量、更新信号量以及在需要时使某个进程睡眠。由于这些动作只需要几条指令,所以屏蔽中断不会带来什么副作用。如果使用多个CPU,则每个信号量应由一个锁变量进行保护。

在.net中实现原子操作的类是 Interlocked类。CAS在.NET中的实现类是Interlocked

Interlocked类主要方法

interlocked是基于CAS操作

CAS操作基于CPU提供的原子操作指令实现。只能保证共享变量操作的原子:

对于Intel X86处理器,可通过在汇编指令前增加LOCK前缀来锁定系统总线,使系统总线在汇编指令执行时无法访问相应的内存地址。而各个编译器根据这个特点实现了各自的原子操作函数。

CAS是一种有名的无锁算法。无锁编程(指C#代码中不加锁,汇编代码会自动加锁),即不适用锁的情况下实现多线程之间的变量同步,也就是在没有现成被阻塞的情况下实现变量的同步。

CompareExchange(ref a ,b,c):比较吧a,c是否相等,如果相等,则用b替换a的值。
CompareExchange<T>(T, T, T)  比较两个指定的引用类型的实例 T 是否相等,如果相等,则替换第一个。好多原子操作都是基于这个函数实现的。
Decrement(): 安全递减1,相当于 i--
Exchange(): 安全交换数据,相当于 a = 30
Increment() :安全递加1,相当于 i++
Add() :安全相加一个数值,相当于 a = a + 3
Read() : 安全读取数值,相等于int a=b

案例:用5个线程从0数到1亿

using System.Diagnostics;

class Program
{
static long counter = 1;
/// <summary>
/// 开5个线程 从0数到1亿
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Parallel.Invoke(f1, f1, f1, f1, f1);
// f1();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(counter);
}
static void f1()
{ for (int i = 1; i <= 10_000_000; i++)
{
Interlocked.Increment(ref counter);
// counter++;
}
} }
//5个线程花费时间 1608ms //单线程 125 ms

本以为5个线程会更快,结果还不如一个线程快。这是什么问题???

因为Interlocked.Increment是采用CAS操作

CAS是一种有名的无锁算法。无锁编程(指编程语言方面),即不适用锁的情况下实现多线程之间的变量同步,也就是在没有现成被阻塞的情况下实现变量的同步。

CAS原理

CAS,是“Compare And Swap”的缩写,中文简称就是“比较并替换”。

在这个机制中有三个核心的参数:

  • 主内存中存放的共享变量的值:V(一般情况下这个V是内存的地址值,通过这个地址可以获得内存中的值)
  • 工作内存中共享变量的副本值,也叫预期值:A
  • 需要将共享变量更新到的最新值:B

如上图中,主存中保存V值,线程中要使用V值要先从主存中读取V值到线程的工作内存A中,然后计算后变成B值,最后再把B值写回到内存V值中。多个线程共用V值都是如此操作。CAS的核心是在将B值写入到V之前要比较A值和V值是否相同,如果不相同证明此时V值已经被其他线程改变,重新将V值赋给A(自旋),并重新计算得到B,如果相同,则将B值赋给V。

值得注意的是CAS机制中的这步步骤是原子性的(从cpu指令层面提供的原子操作),所以CAS机制可以解决多线程并发编程对共享变量读写的原子性问题。

CAS的适用场景

读多写少:如果有大量的写操作,CPU开销可能会过大,因为冲突失败后会不断重试(自旋),这个过程中会消耗CPU

cas操作多出比较和写入内存,所以要耗费太多时间了。而单线程不用Interlocked 直接用缓存的数据进行累加,所以单线程更快。

【C# 线程】 atomic action原子操作|primitive(基元、原语)的更多相关文章

  1. 【C#】C#线程_基元线程的同步构造

    目录结构: contents structure [+] 简介 为什么需要使用线程同步 线程同步的缺点 基元线程同步 什么是基元线程 基元用户模式构造和内核模式构造的比较 用户模式构造 易变构造(Vo ...

  2. 【C#进阶系列】28 基元线程同步构造

    多个线程同时访问共享数据时,线程同步能防止数据损坏.之所以要强调同时,是因为线程同步问题实际上就是计时问题. 不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗 ...

  3. Clr Via C#读书笔记----基元线程同步构造

    线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...

  4. 基元线程同步构造之 Mutes(互斥体)

    互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)). 互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section). 因 ...

  5. 基元线程同步构造之waithandle中 waitone使用

    在使用基元线程同步构造中waithandle中waitone方法的讲解: 调用waithandle的waitone方法阻止当前线程(提前是其状态为Nonsignaled,即红灯),直到当前的 Wait ...

  6. [.net]基元线程同步构造

    /* 基元线程同步构造 用户模式构造: 易变构造(Volatile Construct) 互锁构造(Interlocked Construct):自旋锁(Spinlock) 乐观锁(Optimisti ...

  7. .NET 中,编译器直接支持的数据类型称为基元类型(primitive type).基元类型和.NET框架类型(FCL)中的类型有直接的映射关系.

    .NET 中,编译器直接支持的数据类型称为基元类型(primitive type).基元类型和.NET框架类型(FCL)中的类型有直接的映射关系. The primitive types are Bo ...

  8. 解决c#所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMultipleHandles),并在运行时间很长的操作过程中定期发送消息。 转载

    最近做一个后来程序,启动了事务后有一段操作业务,当运行一段时间后,出现这个异常 CLR 无法从 COM 上下文 0x1b1c38 转换为 COM 上下文 0x1b1da8,这种状态已持续 60 秒.拥 ...

  9. 单线程单元(STA)线程都应使用泵式等待基元

    CLR 无法从 COM 上下文 0x20ad98 转换为 COM 上下文 0x20af08,这种状态已持续 60 秒.拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows ...

随机推荐

  1. SSM项目使用拦截器实现登录验证功能

    SSM项目使用拦截器实现登录验证功能 登录接口实现 public User queryUser(String UserName, String Password,HttpServletRequest ...

  2. gin中绑定uri

    package main import ( "github.com/gin-gonic/gin" "net/http" ) type Person struct ...

  3. gin中间request body绑定到不同的结构体中

    1. 一般通过调用 c.Request.Body 方法绑定数据,但不能多次调用这个方法. package main import ( "fmt" "github.com/ ...

  4. 不难懂------react---Immutable的基本使用

    一.Immutable简介 Immutable Data 就是一旦创建,就不能再被更改的数据.对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象.Immut ...

  5. 绑定方法和隐藏属性之property装饰器

    目录 一:绑定方法 1.绑定给对象的方法 2.绑定给类的方法 3.非绑定方法之静态方法 二,隐藏属性 1.如何隐藏属性 三,property 装饰器 一:绑定方法 1.绑定给对象的方法 class P ...

  6. cobbler最小化安装centos8

    centos8 已经发布了GA版本,迫不及待的想尝鲜了,然后现实总是那么残酷,一直安装失败,具体安装步骤如下: 假设cobbler已配置完成. 1.下载centos8 iso镜像 wget http: ...

  7. ApacheCN C/C++ 译文集(二) 20211204 更新

    编写高效程序的艺术 零.序言 第一部分:性能基础 一.性能和并发性介绍 二.性能测量 三.CPU 架构.资源和性能 四.内存架构和性能 五.线程.内存和并发 第二部分:高级并发 六.并发和性能 七.并 ...

  8. VC 为程序创建唯一标识

    转载请注明来源:https://www.cnblogs.com/hookjc/ 应用: 一台机器上只许运行一个客户端 同一个账号只允许登陆一个客户端 BOOl m_IsRun=false; HANDL ...

  9. vue element InfiniteScroll 无限滚动 入坑记录

    select_law_by_tag() { this.laws_loading.is_loading = true; this.laws_loading.no_more = false; this.e ...

  10. Java线程--BlockingQueue使用

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11871704.html Java线程--BlockingQueue使用 阻塞队列就是内容满了之 ...