【C# 线程】interLocked锁
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锁的更多相关文章
- JAVA语言规范-线程和锁章节之同步、等待和通知
JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...
- GIL与线程互斥锁
GIL 是解释器级别的锁,是限制只有一个原生线程运行,防止多个原生线程之间修改底层的共享数据.而线程互斥锁是防止多个线程同时修改python内存空间的共享数据.
- Java线程:锁
一.锁的原理 Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行的代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁 ...
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...
- Java 线程与锁
Synchronization synchronized语法可以获取锁, 当其他线程持有锁的时候该线程想要获取锁将会进入等待状态, 直到没有其他线程持有该锁 显示使用 synchronized (lo ...
- Java线程与锁
概要:线程的实现方法. 线程调度.线程状态及转换.线程安全(5种分类.3种实现方法.锁优化技术) 进程是OS进行资源分配的基本单位,线程是CPU调度的基本单位. 1.线程的实现方法 可参阅 我是一个进 ...
- java多线程 -- 线程八锁
一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些 ...
- GUC-10 线程八锁
/* * 题目:判断打印的 "one" or "two" ? * * 1. 两个普通同步方法,两个线程,标准打印, 打印? //one two * 2. 新增 ...
- JUC——线程同步锁(锁处理机制简介)
锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...
- GIL线程全局锁 协程
GIL线程全局锁 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务 ...
随机推荐
- Cesium入门11 - Interactivity - 交互性
Cesium入门11 - Interactivity - 交互性 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ ...
- HttpServletRequest类介绍
HttpServletRequest类介绍 1,HttpServletRequest类作用: 每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Req ...
- 学习Java第5天
今天所做的工作: 1.包装类 2.数字处理类 3.ArrayList数组 4.学生信息管理系统样卷(部分) 明天工作安排: 1.完成学生信息管理系统样卷 2.核心技术接口继承,多态 所遇到的问题及解决 ...
- Spring @SessionAttributes注解 @ModelAttribute注解
一.@SessionAttribute详解 如果多个请求之间需要共享数据,就可以使用@SessionAttribute. 配置的方法: 在控制器类上标注@SessionAttribute. 配置需要共 ...
- vue中router与route区别
1.$route对象 $route对象表示当前的路由信息,包含了当前 URL 解析得到的信息.包含当前的路径,参数,query对象等. 1. $route.path 字符串,对应当前路 ...
- AQS源码一窥-JUC系列
AQS源码一窥 考虑到AQS的代码量较大,涉及信息量也较多,计划是先使用较常用的ReentrantLock使用代码对AQS源码进行一个分析,一窥内部实现,然后再全面分析完AQS,最后把以它为基础的同步 ...
- maven的三种项目打包方式----jar,war,pom
1.pom工程:**用在父级工程或聚合工程中.用来做jar包的版本控制.必须指明这个聚合工程的打包方式为pom 2.war工程:将会打包成war,发布在服务器上的工程.如网站或服务.在SpringBo ...
- Nginx 路由转发配置(转)
Nginx 路由转发配置笔记 由于预算有限,只有一台服务器,想要玩的东西不少,所以这个台服务器上会提供多重服务,因此涉及到的nginx转发就必有重要了 由nginx做请求代理,提供多种服务 php搭建 ...
- 对JSP中的Session 简单理解
我的理解: 简单来说,要使用服务器端的session对象,就是要有其对应的key,即sessionid,它只认识sessionid. 下面我说的cookie,url重写或者隐藏表单,都是为了将其对应的 ...
- iOS 模糊、精确搜索匹配功能方法总结 By HL
字符串搜索主要用于UITableView的搜索功能的筛选,过滤,查询 下面是一些流行的搜索查询方法 一.遍历搜索 for循环 根据要求:精确搜索(判读字符串相等) 模糊搜索(字符串包含) 相关知识 ...