本文以InterlockedIncrement为例,来说明Windows Interlocked系列函数的实现原理。
阅读目录 volatile Interlocked ReaderWriterLockSlim volatile 简单来说volatile关键字是告诉c#编译器和JIT编译器,不对volatile标记的字段做任何的缓存 Interlocked MSDN 描述:为多个线程共享的变量提供原子操作。主要函数如下: Interlocked.Increment 原子操作,递增指定变量的值并存储结果。 Interlocked.Decrement 原子操作,递减指定变量的值并存储结果。 Interlocked.Add 原子操作,添加两个整数并用两者的和替换第一个整数 Interlocked.CompareExchange(ref a, b, c); 原子操作,a参数和c currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); } while (startVal
二、代码描述 这个代码很简单,就做了2个事情,1是使用Interlocked.Exchange将_flag变量进行赋值。 2是将Interlocked.Exchange操作后返回的原始值与_flag变量进行对比,如果相等说明这个变量已经被修改过了,表示这里是重入了。如果不是则说明第一次进入此方法。 关于Interlocked.Exchange的解释,见微软官网文档,传送门在此:https://msdn.microsoft.com/zh-cn/library/d3fxt78a.aspx 三、越分析越黑暗 传送门在此 http://referencesource.microsoft.com/#mscorlib/system/threading/interlocked.cs,52be0cc9b3954ae9 四、结语 总结一下: 使用Interlocked做的CAS本身是一个CPU操作。数据是放在CPU的寄存器中做的交换。但是我们判断的变量是个静态全局变量,持有的是这个引用地址。
在 dotnet 里面,可以使用 Interlocked 进行原子命令更改 int 等的值,利用这个特性可以在一个固定足够长长度的数组里面,让多线程无锁等待写入值。 AutoFlushList.cs# 尽管这个实现里面其实是有很多不安全的 一个安全和推荐的做法是在写入的时候禁止有任何的更改内部数组的长度的行为,同时在写入的时候禁止有任何的读取行为 这个快速无序仅写集合的原理是通过 Interlocked public int Capacity { get; } public void Add(T value) { var currentIndex = Interlocked.Increment
Interlocked 类 为多个线程共享的变量提供原子操作。 使用 Interlocked 类,可以在不阻塞线程(lock、Monitor)的情况下,避免竞争条件。 Interlocked 类是静态类,让我们先来看看 Interlocked 的常用方法: 方法 作用 CompareExchange() 比较两个数是否相等,如果相等,则替换第一个值。 } public static void AddOneLock() { for (int i = 0; i < 100_0000; i++) { //sum += 1; Interlocked.Increment } } Interlocked 类 (System.Threading) | Microsoft Learn
基元内核模式
原子性操作
非阻止同步
阻止同步
详解Thread类 中的VolatileRead和VolatileWrite方法和Volatile关键字的作用
Volatile关键字的作用
介绍下Interlocked 相信大家理解了Volatile后对于非阻止同步和原子操作有了更深的认识,接下来的Interlocked虽然也属于非阻止同步但是而后Volatile相比也
有着很大的不同,interlocked 利用了一个计数值的概念来实现同步,当然这个计数值也是属于原子性的操作,每个线程都有机会通过Interlocked
去递增或递减这个计数值来达到同步的效果,同时Interlocked比Volatile更加适应复杂的逻辑和并发的情况 首先让我们了解下Interlocked类的一些重要方法
static long Read()以原子操作形式读取计数值,该方法能够读取当前计数值,但是如果是64位cpu的可以不需要使用该方法读取. 的使用方法
///
目录 知识点 竞争条件 线程同步 CPU时间片和上下文切换 阻塞 内核模式和用户模式 Interlocked 类 1,出现问题 2,Interlocked.Increment() 3,Interlocked.Exchange () 4,Interlocked.CompareExchange() 5,Interlocked.Add() 6,Interlocked.Read() 知识点 竞争条件 当两个或两个以上的线程访问共享数据 这时 Interlocked 就起作用了,对于一些简单的操作运算, Interlocked 可以实现原子性的操作。 说明 Interlocked 可以对简单值类型进行原子操作。 Interlocked.Increment() 是递增,而 Interlocked.Decrement() 是递减。 3,Interlocked.Exchange() Interlocked.Exchange() 实现赋值运算。
示例 C# 中提供了 Interlocked 类来实现 「CAS」 操作。 Interlocked.Increment(ref val):将 val 的值增加 1,并返回增加后的值。 Interlocked.Decrement(ref val):将 val 的值减少 1,并返回减少后的值。 示例代码: int val = 0; Interlocked.CompareExchange(ref val, 1, 0); // val = 1, 返回 0 Interlocked.CompareExchange (ref val, 2, 1); // val 保持 1, 返回 1 Interlocked.Increment(ref val); // val = 2, 返回 2 Interlocked.Decrement
巧妙地使用Interlocked的各个方法,再无锁无阻塞的情况下判断出所有线程的运行完成状态。 引起我注意的是jeffrey在第29章说的:使用Interlocked,代码很短,绝不阻塞任何线程,二期使用线程池线程来实现自动伸缩。 an operation public void AboutToBegin(Int32 opsToAdd = 1) { Interlocked.Add 分析了下AsyncCoordinator类,主要就是利用Interlocked的Add方法,实时计数线程的数量,随后待一个线程运行的最后又调用Interlocked的Decrement方法自减。 如果你留心的话,你会发现,目前绝大多数的并发判断中都用到了Interlocked的这些方法,尤其是interlocked的anything模式下的compareexchange方法,在这里提一嘴,除了compareexchange
= null || Interlocked.CompareExchange(ref _firstItem, obj, null) ! 主要的关键就在Interlocked.CompareExchange方法上,我们在下文来仔细研究一下这个方法。 关于 Interlocked.CompareExchange Interlocked.CompareExchange它实际上是一个CAS的实现,也就是 Compare And Swap,从名字就可以看出来 Interlocked类中的其它方法也是同样的原理,我们可以看看Add之类的方法,同样是在对应的操作指令前加了lock指令。 总结 本文主要是带大家看了下ObjectPool的源码,然后看了看ObjectPool能实现无锁线程安全的最大功臣Interlocked.CompareExchange方法;然后通过汇编代码了解了一下Interlocked
Interlocked可以为多个线程共享的变量提供原子操作。 Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。 Interlocked.Decrement以原子操作的形式递减指定变量的值并存储结果。 Interlocked.Add以原子操作的形式,添加两个整数并用两者的和替换第一个整数 public override T Get() { var item = _firstItem; if (item == null || Interlocked.CompareExchange(ref _firstItem, null, = null || Interlocked.CompareExchange(ref _firstItem, obj, null) !
new List<int>(); Parallel.For(0, 1000 * 10000, r => { while (Interlocked.Exchange { //黑魔法 } li.Add(r); Interlocked.Exchange ; //释放锁 }); Console.WriteLine(li.Count); //输出:10000000 上面就是自旋锁:Interlocked.Exchange ; return; } #else if (Interlocked.CompareExchange 1:内部使用了Interlocked.CompareExchange保持原子操作, m_owner 0可用,1不可用。
value</returns> public int AtomicAddAndGet(int delta) { return Interlocked.Add </returns> public int AtomicIncrementAndGet() { return Interlocked.Increment </returns> public int AtomicDecrementAndGet() { return Interlocked.Decrement </returns> public int AtomicIncrementAndGet() { return Interlocked.Increment </returns> public int AtomicDecrementAndGet() { return Interlocked.Decrement
有经验的同学,立马能想到需要加锁了,C#内置了很多锁对象,如lock 互斥锁,Interlocked 内部锁,Monitor 这几个比较常见,lock内部实现其实就是使用了Monitor对象。 对变量自增,Interlocked对象提供了,变量自增,自减、或者相加等方法,我们使用自增方法Interlocked.Increment,函数定义为:int Increment(ref int num) var m = new ConcurrentBag<int>(); list.AsParallel().ForAll(n => { var c = random.Next(1, 50); Interlocked.Add (ref total, c); for (int i = 0; i < c; i++) { Interlocked.Increment(ref num); x = q.GroupBy(n => n).Where(o => o.Count() > 1); Console.WriteLine($"并发使用安全集合BlockingCollection+Interlocked
current; public long FixedWindow() { var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ct = Interlocked.Read (ref _currentTime); if (now > ct) { if (Interlocked.CompareExchange(ref _currentTime, now, ct)==ct) { Interlocked.Exchange(ref _current, 0); } } return Interlocked.Increment(ref _current); } 代码没多少,每调用一次就返回计数,采用的 C# CAS API Interlocked ,保证每个计数操作都是原子操作
我们来看几段代码: 1 2 3 4 5 var isRunning = Interlocked.CompareExchange(ref _isRunning, 1, 0); if (isRunning 前者使用 Interlocked 做原则操作,而后者使用并发字典。 无论写上面哪一段代码,都面临着问题: 此刻调用的那一句话得到的任何结果都仅仅只表示这一刻,而不代表其他任何代码时的结果。 比如前者的 Interlocked.CompareExchange(ref _isRunning, 1, 0) 我们得到一个返回值 isRunning,然后判断这个返回值。 Interlocked 是原子操作,所以才确保安全。 而后者,此时访问得到的字典数据,和下一时刻访问得到的字典数据将可能完全不匹配,两次的数据不能通用。 虽然我们使用 Interlocked.CompareExchange 原子操作,但因为后面依然涉及到了多次状态的获取,导致不得不加锁才能确保安全。
= null && Interlocked.CompareExchange(ref items[i].Element, null,item) ! return; } var items = _items; for (var i = 0; i < items.Length && Interlocked.CompareExchange 取操作:Interlocked.CompareExchange(ref items[i].Element, null,item)。 取完后将元素置为null 还操作:Interlocked.CompareExchange(ref items[i].Element, obj, null)如果元素为null,则赋值 设计原理:通过Policy
switch (kind) { case ScanKinds.Receipt: //stat.Receipts++; Interlocked.Increment (ref _Sends); break; case ScanKinds.SendBag: Interlocked.Increment(ref (ref _Comes); break; case ScanKinds.ComeBag: Interlocked.Increment(ref (ref _Signs); break; case ScanKinds.Back: Interlocked.Increment(ref _ Backs); break; case ScanKinds.Problem: Interlocked.Increment(ref _Problems
public override T Get() { var item = _firstItem; if (item == null || Interlocked.CompareExchange = null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item) { = null || Interlocked.CompareExchange(ref _firstItem, obj, null) ! = null) { var items = _items; for (var i = 0; i < items.Length && Interlocked.CompareExchange
CallStackContext Current { get => _current; set => _current = value; } public long TraceId { get; } = Interlocked.Increment Current { get => _current.Value; set => _current.Value = value; } public long TraceId { get; } = Interlocked.Increment CallContext.GetData(nameof(CallStackContext)) as CallStackContext; public long TraceId { get; } = Interlocked.Increment CallContext.GetData(nameof(CallStackContext)) as CallStackContext; public long TraceId { get; } = Interlocked.Increment public static CallStackContext Current => _contextAccessor.Value; public long TraceId { get; } = Interlocked.Increment