overview

同步基元分为用户模式和内核模式

用户模式:Iterlocked.Exchange(互锁)、SpinLocked(自旋锁)、易变构造(volatile关键字、volatile类、Thread.VolatitleRead|Thread.VolatitleWrite)、MemoryBarrier。

.net中的System.Threading命名空间的Interlocked类可以为多个线程共享的变量提供原子操作。

经验显示,那些需要在多线程下被保护的资源通常是整型的,而这些被共享的整型值最常见的操作就是增加、减少。Interlocked类提供了一个专门的机制用于完成这些特定的操作。

Iterlocked.Exchange() 不只是原子的,它还具有内存可见性。

所有 方法都生成一个完整的栅栏。因此,您通过访问的字段不需要额外的栅栏。

Interlocked 轻量级锁

Interlocked.Increment(ref value)     数值加一(原子性操作)
Interlocked.Decrement(ref value)     数值减一(原子性操作)
Interlocked.Exchange(ref value1, value2)     交换:把值2赋给值1;返回新值
Interlocked.CompareExchange(ref value1, value2, value3)     实现比较和交换两种功能:值1和值3比较,如果相同,把值2给值1,不相同则不作任何操作;返回原值(多用于判断条件)(示例3中会用到)

Interlocked.MemoryBarrier :按如下方式同步内存存取:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier() 调用之后的内存存取,再执行 MemoryBarrier() 调用之前的内存存取的方式。Thread.MemoryBarrier 就是包装了它。

个人补充:值刷新当前执行线程的cpu上的store buffer和Invalidate queue都运行完成了.

Interlocked.MemoryBarrierProcessWide:内部执行FlushProcessWriteBuffers函数()。该函数功能刷新正在运行当前进程所有线程的每个处理器的写入队列(store buffer)。该函数为属于当前进程关联一部分的所有处理器生成一个处理器间中断 (IPI)。它保证了在一个处理器上对另一个处理器执行的写入操作的可见性。

个人补充:将当前进程下所有线程所在的cpu上的store buffer和Invalidate queue都运行完成了,所以非常耗费时间 。

注意不要传入 volatile类型。

 Interlocked.Add 方法:以原子操作的形式,添加两个整数并用两者的和替换第一个整数。

Add(Int32, Int32)|Add(Int64, Int64)Add|(UInt32, UInt32)|Add(UInt64, UInt64)
对两个 32 位整数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成。

And(Int32, Int32)方法:对两个 32 位带符号整数进行按位“与”运算,并用结果替换第一个整数,上述操作作为一个原子操作完成。
Add(Int32, Int32)|Add(Int64, Int64)Add|(UInt32, UInt32)|Add(UInt64, UInt64)
对两个 32 位带符号整数进行按位“与”运算,并用结果替换第一个整数,上述操作作为一个原子操作完成。

Interlocked.Or 方法:对两个 32 位带符号整数进行按位“或”运算,并用结果替换第一个整数,上述操作作为一个原子操作完成。
Add(Int32, Int32)|Add(Int64, Int64)Add|(UInt32, UInt32)|Add(UInt64, UInt64)
对两个 32 位带符号整数进行按位“或”运算,并用结果替换第一个整数,上述操作作为一个原子操作完成。

Interlocked.Read 方法 :返回一个以原子操作形式加载的 64 位值。
Read(Int64) |Read(UInt64)     
返回一个以原子操作形式加载的 64 位值。

MemoryBarrierProcessWide方法与“普通”MemoryBarrier方法的区别如下:
正常的memory barrier可以确保当前CPU的读写不能跨越barrier。进程级内存屏障确保了进程中使用的任何CPU的任何读或写操作都不能跨越这个屏障。
如果每个访问数据的线程都使用barrier,那么正常的内存barrier允许合理的共享访问。进程级内存屏障迫使其他cpu与进程内存同步(例如,刷新写缓冲区和同步读缓冲区)。这允许在某些线程上进行非连锁操作,并且仍然有合理的共享访问。
正常的内存屏障的开销很小;正常的连锁操作可能花费不到100个周期。进程级内存屏障非常昂贵。它必须迫使进程中的每个CPU做一些事情,可能要花费数千个周期。
MemoryBarrierProcessWide方法还受到无锁编程的所有微妙之处的影响。然而,当您实际需要调用它时,这个方法可能非常有用,这种情况应该很少见。
该方法封装了对Windows上的FlushProcessWriteBuffers和Linux上的sys_membarrier的调用。

案例来自:

这个案例主要考验对 volatile关键字和内存屏障的理解。

该案例会出乎意料的输出0,0 。为了避免该情况必须使用全内存屏障。

该例子来自:volatile的内存屏障的坑

using System;
using System.Threading;
using System.Threading.Tasks; namespace MemoryBarriers
{
class Program
{
static volatile int x, y, a, b;
static void Main()
{
while (true)
{
var t1 = Task.Run(Test1);
var t2 = Task.Run(Test2); Task.WaitAll(t1, t2);
if (a == 0 && b == 0)
{
Console.WriteLine("{0}, {1}", a, b);
} x = y = a = b = 0;
}
} static void Test1()
{
x = 1; //方案一 Interlocked.MemoryBarrier();
//方案二 Interlocked.MemoryBarrierProcessWide(); a = y;
} static void Test2()
{ y = 1; //方案一 Interlocked.MemoryBarrier();
b = x; }
}
}

【C# 线程】interLocked锁的更多相关文章

  1. JAVA语言规范-线程和锁章节之同步、等待和通知

    JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...

  2. GIL与线程互斥锁

    GIL 是解释器级别的锁,是限制只有一个原生线程运行,防止多个原生线程之间修改底层的共享数据.而线程互斥锁是防止多个线程同时修改python内存空间的共享数据.

  3. Java线程:锁

    一.锁的原理 Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行的代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁 ...

  4. (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁

    8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...

  5. Java 线程与锁

    Synchronization synchronized语法可以获取锁, 当其他线程持有锁的时候该线程想要获取锁将会进入等待状态, 直到没有其他线程持有该锁 显示使用 synchronized (lo ...

  6. Java线程与锁

    概要:线程的实现方法. 线程调度.线程状态及转换.线程安全(5种分类.3种实现方法.锁优化技术) 进程是OS进行资源分配的基本单位,线程是CPU调度的基本单位. 1.线程的实现方法 可参阅 我是一个进 ...

  7. java多线程 -- 线程八锁

    一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些 ...

  8. GUC-10 线程八锁

    /* * 题目:判断打印的 "one" or "two" ? * * 1. 两个普通同步方法,两个线程,标准打印, 打印? //one two * 2. 新增 ...

  9. JUC——线程同步锁(锁处理机制简介)

    锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...

  10. GIL线程全局锁 协程

    GIL线程全局锁 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务 ...

随机推荐

  1. 关于启动bash提示‘bash: export: `//这是新的': not a valid identifier’的解决办法

    学习linux以来将centos改的也不少了,也不知道这个问题是由于那个修改来的.最近改bash的操作环境配置文件,用到了~/.bashrc这个文件,发现里面被我修改过. 那是当年安装fcitx输入法 ...

  2. 在3G移动通信网络信令流程里获取用户电话号的一种方法(中国电信cdma2000)

    首先这些关于电话号的的寻找都是在分组域进行的 然后是首先在rp接口的A11接口寻找,没有看到,于是到pi接口,研究radius协议 发现在协议里也不含有与用户电话号码mdn相关的元素 然后偶遇一篇文档 ...

  3. gin中自定义路由日志的格式

    package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" &quo ...

  4. 多线程(Thread类中的方法线程名称)

    1 package multithread; 2 3 /* 4 * 如何创建一个线程呢? 5 * 6 * 创建线程方式一:继承Thread类. 7 * 8 * 步骤: 9 * 1,定义一个类继承Thr ...

  5. 《手把手教你》系列技巧篇(六十一)-java+ selenium自动化测试 - 截图三剑客 -下篇(详细教程)

    1.简介 按照计划宏哥今天将介绍java+ selenium自动化测试截图操作实现的第三种截图方法,也就是截图的第三剑客 - 截取某个元素(或者目标区域)的图片.在测试的过程中,有时候不需要截取整个屏 ...

  6. Android开发----Button组件的使用与练习

    Button 学习目标: 文字大小.颜色 自定义背景形状 自定义按压效果 点击事件 创建一个新的Activity以增加控件 1.文字大小.颜色 直接在xml文件中定义即可 <Button and ...

  7. ApacheCN 编程/大数据/数据科学/人工智能学习资源 2019.12

    公告 我们的所有非技术内容和活动,从现在开始会使用 iBooker 这个名字. "开源互助联盟"已终止,我们对此表示抱歉和遗憾.除非特地邀请,我们不再推广他人的任何项目. 公众号自 ...

  8. ApacheCN Java 译文集 20211012 更新

    Effective Java 中文第三版 1. 考虑使用静态工厂方法替代构造方法 2. 当构造方法参数过多时使用 builder 模式 3. 使用私有构造方法或枚类实现 Singleton 属性 4. ...

  9. react 配置使用less后缀文件

    //安装less less less-loader npm install less less-loader --save-dev 安装完成后,在项目中的config目录下找到webpack.conf ...

  10. 使用Typora+PicGo实现图片自动上传到Gitee图床

    一.前言 我们在使用Typora编辑器时,会加上图片,有个弊端,只能在本地访问,你发送给别人就无法查看图片,当然可以导出pdf.小编这边的需求是这样的,自己搭建的一个博客系统,基于Hexo搭建的,这个 ...