C#内置提供的原子操作

  1. Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。
  2. Interlocked.Decrement:以原子操作的形式递减指定变量的值并存储结果。
  3. Interlocked.Add:以原子操作的形式,添加两个整数并用两者的和替换第一个整数

问题:如果要进行原子的乘法、除法或者其他操作改怎么办,C#并没有内置提供相应的方法呀?

那我们先来大概理解一下原子操作的流程

以增加变量值为例

  1. 将实例变量添加到CPU寄存器中
  2. 将该变量的值进行增加
  3. 将该变量的增加后的值从CPU寄存器中还原到堆或栈中实例变量的值

可以看到如果是多核CPU在多线程环境下可能会导致在执行完步骤1,步骤2后当前线程失去时间片,其他线程读取改变量的值时就会读取到并未增加增加之前的值,所以就导致了数据的不一致。然而C#提供了上面三种原子操作来保证不出现这样的数据不一致,至于底层原理暂时不深究,我们来看看如何实现除这三种方法之外的操作。

进行原子的获取最大值操作

先放代码如下:

  public static int Maximum(ref int target, int value)
{
//注意target前面加了 ref ,这样在方法外改变target的值将会影响到方法内的target值,
//即类似按引用传递
int currentVal = target;//使用currentVal局部变量来存储target值,target值的变更不会影响currentVal
int startVal = 0;
int desiredVal = 0; do
{
startVal = currentVal; //记录本次迭代的起始值 1
desiredVal = Math.Max(startVal, value);//根据startVal和value计算最大值desiredVal 2
//如果target和startVal值一致则用desiredVal赋值给target,并将target原始值进行返回
//如果target和startVal值不相同则什么都不做,并将target的值进行返回
//target的值因为在别的线程进行操作时可能改变target的值,所以导致target值和startVal不一致
currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);// 3
} while (startVal != currentVal); // 4
//因为startVal记录的是开始时target的值,而currentVal记录的则是target最新值
//如果startVale和currentVal不一致则代表其他线程已经更改的target的值,所以需要重新迭代。
//重新迭代时currentVal代表的是target的最新值
//疑问:如果在 3 之后 4之前 target的值被其他线程更改怎么办?请大神帮忙
return desiredVal;
}

大致的逻辑可以参考注释进行理解,最主要的方法是通过currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); 可以参考MSDN此方法的解释

其他操作

C# VIA CLR中给出了其他操作的模板,可以参考如下:


delegate int Morpher<TResult, TArgument>(int startValue, TArgument argument, out TResult morphResult); static TResult Morph<TResult,TArgument>(ref int target,TArgument argument,Morpher<TResult,TArgument> morpher)
{
TResult morphResult;
int currentVal = target;
int startVal = 0;
int desiredVal = 0;
do
{
startVal = currentVal;
desiredVal = morpher(startVal, argument, out morphResult);
currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);
} while (startVal != currentVal);
return morphResult; }

可以通过委托定义自己想要的操作。乘法、除法等等。

大神写出的书就是牛,膜拜Jeffrey Richter

C# 原子操作理解的更多相关文章

  1. 十、future其他成员函数、shared_future、atomic(原子操作)

    一. int mythread(){ cout<<"thread"<<endl; std::chrono::milliseconds dura();//5秒 ...

  2. 深入理解Atomic原子操作和volatile非原子性

    原子操作可以理解为: 一个数,很多线程去同时修改它,不加sync同步锁,就可以保证修改结果是正确的 Atomic正是采用了CAS算法,所以可以在多线程环境下安全地操作对象. volatile是Java ...

  3. 深入理解java:2.3.1. 并发编程concurrent包 之Atomic原子操作(循环CAS)

    java中,可能有一些场景,操作非常简单,但是容易存在并发问题,比如i++, 此时,如果依赖锁机制,可能带来性能损耗等问题, 于是,如何更加简单的实现原子性操作,就成为java中需要面对的一个问题. ...

  4. 关于P,V操作理解的突破,关于并发设计与并行

    今天又找了一篇博客研究P,V操作.. 发现..它有一个变量没有声明.. 我就换了篇博客..http://c.biancheng.net/cpp/html/2600.html 然后就看懂了.. 关键突破 ...

  5. sun.misc.Unsafe的理解

    以下sun.misc.Unsafe源码和demo基于jdk1.7: 最近在看J.U.C里的源码,很多都用到了sun.misc.Unsafe这个类,一知半解,看起来总感觉有点不尽兴,所以打算对Unsaf ...

  6. pthread_cond_wait()函数的理解(摘录)

    /************pthread_cond_wait()的使用方法**********/pthread_mutex_lock(&qlock);    /*lock*/pthread_c ...

  7. SOA架构介绍和理解

    SOA架构介绍和理解 SOA的正确方法论及目标模型,其实SOA在实现架构落地上,需要考虑到对服务的组合,不断的重用现有的服务,让企业应用可以逐步集成,快速实现业务的迭代. 通过SOA架构分层将服务按照 ...

  8. 【Todo】【转载】深入理解Java内存模型

    提纲挈领地说一下Java内存模型: 什么是Java内存模型 Java内存模型定义了一种多线程访问Java内存的规范.Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几 ...

  9. oracle rac理解和用途扩展

    Oracle RAC的优势在于利用多个节点(数据库实例)组成一个数据库,这样在保证了数据库高可用性的情况下更充分的利用了多个主机的性能,而且可以通过增加节点进行性能的扩展.实现Oracle RAC需要 ...

随机推荐

  1. STM32 F4xx Fault 异常错误定位指南

    STM32 F407 采用 Cortex-M4 的内核,该内核的 Fault 异常可以捕获非法的内存访问和非法的编程行为.Fault异常能够检测到以下几类非法行为: 总线 Fault: 在取址.数据读 ...

  2. 1+x 证书 Web 前端开发初级理论考试(试卷8 )

    Web前端开发初级模拟测试卷(三) 共55道题 总分:200分 形考总分:0分 一.单选题共30题,60分 1.实现向右的红色三角形,样式实现正确的是( ) A <div class=" ...

  3. EggJs快速入门

    Egg.js 简介 Egg.js 为企业级框架和应用而生,帮助开发团队和开发人员降低开发和维护成本. 专注于提供 Web 开发的核心功能和一套灵活可扩展的插件机制,不会做出技术选型,因为固定的技术选型 ...

  4. Rust开发环境搭建

    1.Rust概述 按照百度百科的说法,Rust是一门系统编程语言 ,专注于安全 ,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言.Rust在语法上和C++类似 ,但是设计者想要在保证 ...

  5. asp.net core web api 生成 swagger 文档

    asp.net core web api 生成 swagger 文档 Intro 在前后端分离的开发模式下,文档就显得比较重要,哪个接口要传哪些参数,如果一两个接口还好,口头上直接沟通好就可以了,如果 ...

  6. 使用 C# 实现 CJ-T188 水表协议和 DL-T645 电表协议的解析与编码

    一.协议的定义 要对某种协议进行编解码操作,就必须知道协议的基本定义,首先我们来看一下 CJ/T188 的数据帧定义(协议定义),了解请求数据与响应数据的基本结构. 1.1 CJ/T188 水表通讯协 ...

  7. pycharm 新建py文件写时有作者和时间

    ##!/usr/bin/python3 # -*- coding: utf-8 -*- ''' @Time : ${DATE} ${TIME} @Author : YourName @FileName ...

  8. MySQL的基本概念和数据操作

    1.连接服务器 数据库是CS模式的软件,所以要连接数据库必须要有客户端软件.MySQL数据库默认端口号是3306         1.1window界面连接服务器         1.2通过web窗体 ...

  9. 软件设计之基于Java的连连看小游戏(二)——游戏基础界面的制作及事件的添加

    上次完成到游戏首页的制作,今天完成了游戏基础界面的制作以及事件的简单添加.由于功能尚未完全实现,因此游戏界面的菜单列表只是简单地添加了一下,其余菜单列表以及倒计时等在后续的制作中逐一完善. 1.首先在 ...

  10. mssql下调用dll

    1.新建类库,里面写入方法,类库里必须样静态,防止实例化 2.将dll存放到文件夹里 3.在sql中运行 EXEC sp_configure 'clr enabled' , '1'; --0代表不允许 ...