C# Interlocked 原子操作

作者 : admin 本文共4581个字,预计阅读时间需要12分钟 发布时间: 2024-06-8 共5人阅读

目录

注解

方法

适用于

案例

 1:Add 对两个整数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成

2:Exchange  Exchange(UInt32, UInt32)  以原子操作的形式,将 32 位无符号整数设置为指定的值并返回原始值。


参考文档:Interlocked 类 (System.Threading) | Microsoft Learn

我对Interlocked原子操作的理解是:如同一桌人喝一碗汤,汤碗里面有一个公用的勺子,不能多个人同时使这把公用的勺子舀汤,  当有人想喝汤时(或者服务员想要加汤时),就得先拿到勺子,其他人就没法喝汤(或者添汤)。只有喝汤的人(添汤的人)用完勺子放回汤碗后,其他人才能继续使用勺子喝汤(添汤)。

注解

此类的方法可帮助防止在以下情况下发生的错误:在以下情况下发生:计划程序在以下情况下切换上下文:当线程正在更新可被其他线程访问的变量时,或当两个线程同时在不同的处理器上执行时。 此类的成员不会引发异常。

Increment和 Decrement 方法递增或递减变量,并在单个操作中存储生成的值。 在大多数计算机上,递增变量不是原子操作,需要执行以下步骤:

  1. 将实例变量中的值加载到寄存器中。

  2. 递增或减小值。

  3. 将值存储在实例变量中。

如果不使用 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 位无符号整数是否相等,如果相等,则替换第一个值。

(T, T, T)”>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 位无符号整数设置为指定的值并返回原始值。

(T, T)”>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
.NET5.0
.NET Core1.0, 1.1, 2.0, 2.1, 2.2, 3.0, 3.1
.NET Framework1.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 Standard1.0, 1.1, 1.2, 1.3, 1.4, 1.6, 2.0, 2.1
UWP10.0
Xamarin.Android7.1
Xamarin.iOS10.8
Xamarin.Mac3.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;
            }
        }
    }

执行结果

C# Interlocked 原子操作插图

本站无任何商业行为
个人在线分享 » C# Interlocked 原子操作
E-->