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. virtual studio发布到gihub

    问题 我们想要发布代码到github或者微软团队服务时候,往往发现没有本地库,所以难以发布. 解决方案 在解决方右击就可以新建git 文件都会出现小锁说明有了记录 文件夹会对应出现 右上角管理连接也会 ...

  2. vue学习11-监听属性

    <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <meta http ...

  3. 面渣逆袭:Java基础五十三问,快来看看有没有你不会的!

    大家好,我是老三, 面渣逆袭 系列继续.这节我们回到梦开始的地方--Java基础,其实过了萌新阶段,面试问基础就问的不多,但是保不齐突然问一下.想一下,总不能张口高并发.闭口分布式,结果什么是面向对象 ...

  4. PyTorch 介绍 | DATSETS & DATALOADERS

    用于处理数据样本的代码可能会变得凌乱且难以维护:理想情况下,我们希望数据集代码和模型训练代码解耦(分离),以获得更好的可读性和模块性.PyTorch提供了两个data primitives:torch ...

  5. 学习Java第9天

    今天所作的工作: 反射,枚举类型与泛型 明天工作: 1.线程 2.网络通信 所遇到的问题及解决方法: 反射基本思想,泛型类似于类模板. 理解反射太难了,转悠了好半天,关键是理解反射的思想,才容易学.

  6. Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  7. flask学习1

    总结 Flask Web 框架 轻量 websocket 全双工通讯 socket TCP 通讯 MongoDB 数据库 文件型数据库 {} 没有限制 和 约束 Mui + HTML5 Plus 调用 ...

  8. 「JOISC 2014 Day4」两个人的星座

    首先突破口肯定在三角形不交,考虑寻找一些性质. 引理一:两个三角形不交当且仅当存在一个三角形的一条边所在直线将两个三角形分为异侧 证明可以参考:三角形相离充要条件,大致思路是取两个三角形重心连线,将其 ...

  9. Idea中新建package包,却变成了Directory

    问题描述 今天在IdeaJava工程src下新建了一个名字叫包implements的包,右键在里面新建类时,却发现根本就没有Class这个选项,然后发现implements这个包的图标也和其他包的图标 ...

  10. git reset HEAD 与 git reset --hard HEAD的区别

    感谢原文作者:天地逍遥 原文链接:https://www.jianshu.com/p/aeb50b94e6c0 git reset HEAD 是将咱暂存区和HEAD的提交保持一致 git reset ...