C# 原子操作 Interlocked

喜夏-厌秋 提交于 2020-01-20 21:53:16

前言

焦虑与恐惧,往往是是因为想要的太多,但行动却太少。将目标放低,制定足以达到目标的计划,并付之于一步一个脚印的行动。当你确信你在前进的时候,自然就不会焦虑;当你的行动为你积累了足够多的正向改变的时候,自然就不会恐惧;当量变中迸发出那么一星星的质变时,你将变的自信。

足够强大,你才会自信。自信来源于强大的内心,强大的自己

开始

Interlocked 提供了方法来实现原子操作,对于多线程共享的变量来说,原子操作保证了线程安全,保证了变量值的正确性。

让我们看一个简单的例子,在下面例子中,我们 new 了 10 个 线程,并启动他们;他们各自循环10次调用 UseSharedValue 方法;在 UseSharedValue 方法中, 我们执行了 threadSharedValue++ 的操作。由于 threadSharedValue 的初始值为0,所以当程序跑完后,我们对于 threadSharedValue 的期望值为100。

using System;
using System.Threading;

namespace InterlockedExchange_Example
{
    class MyInterlockedExchangeExampleClass
    {
        private static int threadSharedValue = 0;
        //每个线程内,循环10次
        private const int numThreadIterations = 10;
        //线程数为10 
        private const int numThreads = 10;
        static void Main()
        {
            Thread myThread;
            for (int i = 0; i < numThreads; i++)
            {
                myThread = new Thread(new ThreadStart(MyThreadProc));
                myThread.Start();
            }
            Console.Read();
        }

        private static void MyThreadProc()
        {
            for (int i = 0; i < numThreadIterations; i++)
            {
                UseSharedValue();
            }
        }

        static void UseSharedValue()
        {
            Thread.Sleep(100);
            threadSharedValue++;
            Thread.Sleep(100);
            Console.WriteLine(threadSharedValue);
        }

    }
}

可以新建控制台程序,并将上面代码复制到 Program.cs 来覆盖原来代码,然后F5运行程序。得到 threadSharedValue 的最终结果可能是 95,也可能是97,很小几率会出现我们的期望值100.

于是我们想到了这可能是因为线程之间的互相干扰导致的。可能2个线程同时执行 threadSharedValue ++ 操作,假设 threadSharedValue 当前为10,则两个线程都判断它原始值为10, ++后值为11。这种情况每出现一次,我们最终得到的 threadSharedValue 的结果就比100少1. 所以在多次执行该程序后,得到的结果总是比100少一点。

为了解决这种问题,我们想到了使用线程锁,在一个线程访问 threadSharedValue 的值时,禁止另外的线程同时访问。 .net 准备了 System.Threading.Interlocked 类 来实现原子操作,从而保证 线程共享变量 的 线程安全。

在上面的例子中,将

        threadSharedValue++;

替换为

        Interlocked.Increment(ref threadSharedValue);

重新执行程序,发现 threadSharedValue 的最终值 始终为 100.

Interlocked 常用方法有:

// 加1,原子操作,线程安全
Increment( ref Int32 ) ,
Increment( ref Int64 ) ,

// 减1,原子操作,线程安全 
Decrement( ref Int32),
Decrement( ref Int64),

// 把第二个参数加到 ref 值上
Add ( ref Int32, Int32 ),
Add ( ref Int64, Int64 ),

// 把第二个参数赋值给 ref 值
Exchange ( ref Int32, Int32 ),
Exchange ( ref Int64, Int64 ),

关于 Interlocked 的更多知识,可以查看官方提供的文档,本文末尾的参考文档中提供了链接地址。

参考文档

https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=netframework-4.8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!