目录
注解
方法
适用于
案例
1:Add 对两个整数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成
2:Exchange Exchange(UInt32, UInt32) 以原子操作的形式,将 32 位无符号整数设置为指定的值并返回原始值。
参考文档:Interlocked 类 (System.Threading) | Microsoft Learn
我对Interlocked原子操作的理解是:如同一桌人喝一碗汤,汤碗里面有一个公用的勺子,不能多个人同时使这把公用的勺子舀汤, 当有人想喝汤时(或者服务员想要加汤时),就得先拿到勺子,其他人就没法喝汤(或者添汤)。只有喝汤的人(添汤的人)用完勺子放回汤碗后,其他人才能继续使用勺子喝汤(添汤)。
注解
此类的方法可帮助防止在以下情况下发生的错误:在以下情况下发生:计划程序在以下情况下切换上下文:当线程正在更新可被其他线程访问的变量时,或当两个线程同时在不同的处理器上执行时。 此类的成员不会引发异常。
Increment和 Decrement 方法递增或递减变量,并在单个操作中存储生成的值。 在大多数计算机上,递增变量不是原子操作,需要执行以下步骤:
-
将实例变量中的值加载到寄存器中。
-
递增或减小值。
-
将值存储在实例变量中。
如果不使用 Increment 和,则在 Decrement 执行前两个步骤后,线程可以被抢占。 然后,另一个线程可以执行所有三个步骤。 当第一个线程继续执行时,它将覆盖实例变量中的值,并且由第二个线程执行的增量或减量的影响将丢失。
Add方法以原子方式将整数值添加到整数变量中,并返回变量的新值。
Exchange方法以原子方式交换指定变量的值。 CompareExchange方法组合了两个操作:比较两个值,并根据比较结果将第三个值存储在一个变量中。 比较和交换操作以原子操作的方式执行。
确保对共享变量的任何写入或读取访问都是原子的。 否则,数据可能已损坏,或者加载的值可能不正确。
方法
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) | 比较指定的引用类型 |
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) | 以原子操作的形式,将指定类型 |
Increment(Int32) | 以原子操作的形式递增指定变量的值并存储结果。 |
Increment(Int64) | 以原子操作的形式递增指定变量的值并存储结果。 |
Increment(UInt32) | 以原子操作的形式递增指定变量的值并存储结果。 |
Increment(UInt64) | 以原子操作的形式递增指定变量的值并存储结果。 |
MemoryBarrier() | 按如下方式同步内存存取:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier() 调用之后的内存存取,再执行 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 位无符号值。 |
适用于
产品 | Versions |
---|---|
.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 |
案例
1:Add
对两个整数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成
2: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);
}
}
//A simple method that denies reentrancy.
static bool UseResource()
{
//0 indicates that the method is not in use.
if (0 == Interlocked.Exchange(ref usingResource, 1))
{
Console.WriteLine($"{Thread.CurrentThread.Name} 获得资源");
//这里放 用于访问非线程安全的资源代码。
//模仿 执行的任务,暂停500毫秒
Thread.Sleep(500);
Console.WriteLine($"{Thread.CurrentThread.Name} 释放资源");
//Release the lock
Interlocked.Exchange(ref usingResource, 0);
return true;
}
else
{
Console.WriteLine($" {Thread.CurrentThread.Name} 拿资源时,被拒绝");
return false;
}
}
}
执行结果