C# Interlocked 原子操作详解
创作时间:
作者:
@小白创作中心
C# Interlocked 原子操作详解
引用
CSDN
1.
https://blog.csdn.net/oopxiajun2011/article/details/113253410
Interlocked原子操作简介
在多线程编程中,原子操作是一种不可中断的操作,它保证了在执行过程中不会被其他线程干扰。在C#中,Interlocked
类提供了一系列的原子操作方法,可以确保对共享变量的访问是线程安全的。
概念理解
可以将原子操作理解为多人共用一碗汤的场景:汤碗里有一把公用的勺子,当有人想喝汤时(或服务员想要加汤时),必须先拿到勺子,其他人则无法使用。只有当当前使用者用完勺子并放回后,其他人才能继续使用。这种机制确保了在任何时刻只有一个线程能够访问共享资源,从而避免了数据竞争和不一致的问题。
Interlocked类的主要功能
- 防止上下文切换错误:在多线程环境中,当一个线程正在更新可被其他线程访问的变量时,如果不使用原子操作,可能会导致数据损坏或加载错误的值。
- 确保操作的原子性:
Interlocked
类的方法可以确保对共享变量的读写操作是原子的,不会被其他线程中断。
Interlocked类的主要方法
增加操作
Add(Int32, Int32)
:对两个32位整数求和,并用和替换第一个整数。Add(Int64, Int64)
:对两个64位整数求和,并用和替换第一个整数。Add(UInt32, UInt32)
:对两个32位无符号整数求和,并用和替换第一个整数。Add(UInt64, UInt64)
:对两个64位无符号整数求和,并用和替换第一个整数。
位操作
And(Int32, Int32)
:对两个32位带符号整数进行按位“与”运算,并用结果替换第一个整数。And(Int64, Int64)
:对两个64位带符号整数进行按位“与”运算,并用结果替换第一个整数。And(UInt32, UInt32)
:对两个32位无符号整数进行按位“与”运算,并用结果替换第一个整数。And(UInt64, UInt64)
:对两个64位无符号整数进行按位“与”运算,并用结果替换第一个整数。
比较交换
CompareExchange(Double, Double, Double)
:比较两个双精度浮点数是否相等,如果相等则替换第一个值。CompareExchange(Int32, Int32, Int32)
:比较两个32位有符号整数是否相等,如果相等则替换第一个值。CompareExchange(Int64, Int64, Int64)
:比较两个64位有符号整数是否相等,如果相等则替换第一个值。CompareExchange(IntPtr, IntPtr, IntPtr)
:比较两个平台特定的句柄或指针是否相等,如果相等则替换第一个。CompareExchange(Object, Object, Object)
:比较两个对象是否引用相等,如果相等则替换第一个对象。CompareExchange(Single, Single, Single)
:比较两个单精度浮点数是否相等,如果相等则替换第一个值。CompareExchange(UInt32, UInt32, UInt32)
:比较两个32位无符号整数是否相等,如果相等则替换第一个值。CompareExchange(UInt64, UInt64, UInt64)
:比较两个64位无符号整数是否相等,如果相等则替换第一个值。CompareExchange<T>(T, T, T)
:比较指定的引用类型T的两个实例是否引用相等,如果相等则替换第一个。
增减操作
Decrement(Int32)
:以原子操作的形式递减指定变量的值并存储结果。Decrement(Int64)
:以原子操作的形式递减指定变量的值并存储结果。Decrement(UInt32)
:以原子操作的形式递减指定变量的值并存储结果。Decrement(UInt64)
:以原子操作的形式递减指定变量的值并存储结果。
交换操作
Exchange(Double, Double)
:以原子操作的形式,将双精度浮点数设置为指定的值并返回原始值。Exchange(Int32, Int32)
:以原子操作的形式,将32位有符号整数设置为指定的值并返回原始值。Exchange(Int64, Int64)
:以原子操作的形式,将64位有符号整数设置为指定的值并返回原始值。Exchange(IntPtr, IntPtr)
:以原子操作的形式,将平台特定的句柄或指针设置为指定的值并返回原始值。Exchange(Object, Object)
:以原子操作的形式,将对象设置为指定的值并返回对原始对象的引用。Exchange(Single, Single)
:以原子操作的形式,将单精度浮点数设置为指定的值并返回原始值。Exchange(UInt32, UInt32)
:以原子操作的形式,将32位无符号整数设置为指定的值并返回原始值。Exchange(UInt64, UInt64)
:以原子操作的形式,将64位无符号整数设置为指定的值并返回原始值。Exchange<T>(T, T)
:以原子操作的形式,将指定类型T的变量设置为指定的值并返回原始值。
增加操作
Increment(Int32)
:以原子操作的形式递增指定变量的值并存储结果。Increment(Int64)
:以原子操作的形式递增指定变量的值并存储结果。Increment(UInt32)
:以原子操作的形式递增指定变量的值并存储结果。Increment(UInt64)
:以原子操作的形式递增指定变量的值并存储结果。
内存屏障
MemoryBarrier()
:同步内存存取,确保当前线程的处理器不会重新排序内存存取指令。MemoryBarrierProcessWide()
:提供覆盖整个过程的内存屏障,确保来自任何CPU的读写都不能越过该屏障。
位操作
Or(Int32, Int32)
:对两个32位带符号整数进行按位“或”运算,并用结果替换第一个整数。Or(Int64, Int64)
:对两个64位带符号整数进行按位“或”运算,并用结果替换第一个整数。Or(UInt32, UInt32)
:对两个32位无符号整数进行按位“或”运算,并用结果替换第一个整数。Or(UInt64, UInt64)
:对两个64位无符号整数进行按位“或”运算,并用结果替换第一个整数。
读取操作
Read(Int64)
:返回一个以原子操作形式加载的64位值。Read(UInt64)
:返回一个以原子操作形式加载的64位无符号值。
适用版本
- .NET 5.0
- .NET Core 1.0, 1.1, 2.0, 2.1, 2.2, 3.0, 3.1
- .NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8
- .NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.6, 2.0, 2.1
- UWP 10.0
- Xamarin.Android 7.1
- Xamarin.iOS 10.8
- Xamarin.Mac 3.0
使用案例
Exchange方法示例
下面是一个使用Interlocked.Exchange
方法实现线程安全资源访问控制的示例:
public class InterlockedExchange
{
// 0 表示资源未被使用,1 表示资源被占用
private static int usingResource = 0;
// 每个线程执行次数
private const int numThreadIterations = 5;
// 线程数
private const int numThreads = 10;
public static void Main1()
{
Thread myThread;
Random rnd = new Random();
for (int i = 0; i < numThreads; i++)
{
myThread = new Thread(new ThreadStart(MyThreadProc));
myThread.Name = String.Format($"Thread{i + 1}");
// 在开始下一个线程之前随机等待一段时间
Thread.Sleep(rnd.Next(0, 1000));
myThread.Start();
}
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("主线程已执行完");
Console.ResetColor();
}
private static void MyThreadProc()
{
while (true)
{
// 如果任务拿到资源执行
if (UseResource()) break;
// 等待1秒再执行
Thread.Sleep(1000);
}
}
// 一个简单的拒绝重入的方法
static bool UseResource()
{
// 0 表示方法未在使用
if (0 == Interlocked.Exchange(ref usingResource, 1))
{
Console.WriteLine($"{Thread.CurrentThread.Name} 获得资源");
// 这里放用于访问非线程安全的资源代码
// 模仿执行的任务,暂停500毫秒
Thread.Sleep(500);
Console.WriteLine($"{Thread.CurrentThread.Name} 释放资源");
// 释放锁
Interlocked.Exchange(ref usingResource, 0);
return true;
}
else
{
Console.WriteLine($" {Thread.CurrentThread.Name} 拿资源时,被拒绝");
return false;
}
}
}
执行结果如下:
热门推荐
普通人有50万存款,应该如何稳健理财?内行人给出答案
适合一个人干的地摊小生意有哪些?这些小本项目不容错过
职业健康管理基本原则
应对低血糖:您需要了解什么
全球咖啡瞄准中国3000亿大市场|进博新机遇
电商系统业务剖析:5大核心模块详解
中职生提升专业技能,这样做更有效!
地铁,不是你想待多久,就可以待多久
多肽合成:从基础原理到应用技术的全面探讨
中子星究竟有多可怕?每立方厘米重20亿吨,若人到中子星上会怎样
读博对体制内的人有哪些好处?
芝麻酱钙含量虽高,但专家建议每天食用量不超过一勺
高中留学美国费用到底是多少
四季皆牧歌:阿勒泰千年游牧转场文化的现代传承
体质虚弱怎么调理最好?从日常细节做起!
复旦大学揭牌神经调控与脑机接口研究中心
美国就医案例:晚期结肠癌、肝转移患者,从至多活一年,到到无癌状态,怎么做到的?
如何查看虚拟机里是否安装了nfs
为什么建议避免在正式场合穿"便宜衣服"?看对比图就知道
《星露谷物语》铜矿石获取攻略
项目管理上如何办理工程量签单
宇宙的声音:《张朝阳的物理课》探索广义相对论下的线性引力波
Excel两个表怎么找出遗漏
乱了!王皓马琳点赞尹肖,疑站恩师对立面 张继科:我挺吴敬平
股息率最高的10家公司(2025最新版)
什么是岗位场景需求管理
服务器调试口,如何有效利用以优化性能?
VLOOKUP函数保姆级教程-1对多查询!
哮喘意识:新加坡哮喘管理导航
重庆文旅:打造更多标志性成果 重彩描绘“诗与远方”