Interlocked.Increment 方法 和Interlocked.Decrement 方法作用

简介: Interlocked.Increment 方法:让++成为原子操作;Interlocked.Decrement 方法让--成为原子操作。什么叫原子操作呢。就是不会被别人打断,因为C#中的一个语句,编译成机器代码后会变成多个语句。

Interlocked.Increment 方法:让++成为原子操作;Interlocked.Decrement 方法让--成为原子操作。
什么叫原子操作呢。就是不会被别人打断,因为C#中的一个语句,编译成机器代码后会变成多个语句。
在多线程环境中,线程切换有可能会发生在这多个语句中间。使用Interlocked.Increment,Interlocked.Decrement 可以避免被打断,保证线程安全。

使用Interlocked.Increment 方法和Interlocked.Decrement 方法MSND例子:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
        Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
        thread1.Start();
        thread2.Start();
        thread1.Join();
        thread2.Join();

        // Have the garbage collector run the finalizer for each
        // instance of CountClass and wait for it to finish.
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("UnsafeInstanceCount: {0}" +
            "\nSafeCountInstances: {1}",
            CountClass.UnsafeInstanceCount.ToString(),
            CountClass.SafeInstanceCount.ToString());
    }

    static void ThreadMethod()
    {
        CountClass cClass;
       
        // Create 100,000 instances of CountClass.
        for(int i = 0; i < 100000; i++)
        {
            cClass = new CountClass();
        }
    }
}

class CountClass
{
    static int unsafeInstanceCount = 0;//不使用原子操作
    static int   safeInstanceCount = 0;//使用原子操作

    static public int UnsafeInstanceCount
    {
        get {return unsafeInstanceCount;}
    }

    static public int SafeInstanceCount
    {
        get {return safeInstanceCount;}
    }

    public CountClass()
    {
        unsafeInstanceCount++;
        Interlocked.Increment(ref safeInstanceCount);
    }

    ~CountClass()
    {
        unsafeInstanceCount--;
        Interlocked.Decrement(ref safeInstanceCount);
    }
}

不用原子操作例子

class Program
    {
       
static void Main(string[] args)
        {
           
for (int loop = 0; loop < 20; loop++)
            {
                sum
= 0;
                Thread t1
= new Thread(Thread1);
                Thread t2
= new Thread(Thread2);
                t1.Start();
                t2.Start();

                t1.Join();
                t2.Join();
                Console.WriteLine(
"sum = " + sum);         // sum = 200000 ?
            }
        }

       
static int sum;
       
static void Thread1()
        {
           
for (int i = 0; i < 100000; i++) sum++;
        }
       
static void Thread2()
        {
           
for (int i = 0; i < 100000; i++) sum++;
        }
    }

结果:

/*
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 192361
sum = 175155
sum = 200000
sum = 176024
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 200000
sum = 176322
*/
Why the sum is not always 200000?
The reason is that sum++ is not thread safe (see the possible problem).
That is the reason we need Interlocked.Increment(), which guarantees the sum is always 200000.

Thread1 (sum++)                   Thread2 (sum++)
--------------------------------------------------------------------
mov   EAX, dword ptr sum          .
inc   EAX                         .
.                                 mov   EAX, dword ptr sum          
// load sum into a register
.                                 inc   EAX                          // increase it
.                                 mov   dword ptr sum, EAX           // save back
mov   dword ptr sum, EAX
--------------------------------------------------------------------

problem: two sum
++ are called in different thread,
but the sum
is incremented only once.
也就是说因为C#中的一个语句,编译成机器代码后会变成多个语句,线程不安全,sum++的第100次操作就被打断了,而在第200000次++操作结束后CPU才轮询到sum++的第100次操作,这时sum的值就是101,



相关文章
|
缓存
IDEA找不到或无法加载主类
IDEA找不到或无法加载主类
4178 0
IDEA找不到或无法加载主类
|
6月前
|
运维 Ubuntu Linux
Linux重置root用户密码
本文详细介绍了Linux系统中root密码重置的核心技能,涵盖主流发行版如RHEL、CentOS、Debian、Ubuntu、Arch、openSUSE等的实操方法。内容包括通过GRUB引导编辑、单用户模式和Live CD救援三种方式重置密码的具体步骤,适配物理机、虚拟机及云服务器环境。文章分步解析了启动拦截、权限获取和密码重置三大阶段,并提供各发行版的实际操作代码示例,帮助管理员快速解决忘记root密码的问题。
|
10月前
|
传感器 人工智能 算法
《流形学习:破解人工智能复杂数据处理难题的利刃》
流形学习降维算法,如Isomap和LLE,通过挖掘数据的内在几何结构,有效应对高维图像、文本和传感器等复杂数据带来的挑战。Isomap基于测地线距离保持全局结构,LLE则侧重局部线性重构,二者在人脸识别、生物医学数据分析、自然语言处理及传感器数据分析等领域展现出独特优势。尽管面临计算复杂度和噪声影响等挑战,流形学习仍为复杂数据处理提供了强大工具,未来结合深度学习等技术将有更广泛应用前景。
346 10
|
监控 安全 网络安全
如何构建安全的网络基础设施:全面指南
【8月更文挑战第2天】构建安全的网络基础设施是一个复杂而持续的过程,需要企业从规划、设计、实施到维护等各个环节都给予足够的重视和投入。通过全面的风险评估、合理的安全策略、科学的设计方案、严格的实施流程和持续的监控优化,可以为企业打造一个坚不可摧的网络安全防线。在这个过程中,企业应始终保持对新技术和新威胁的敏锐洞察力,不断优化和完善安全体系,确保网络基础设施的安全稳定运行。
|
设计模式 Java
设计模式在Java项目中的实际应用
设计模式在Java项目中的实际应用
194 10
|
机器学习/深度学习 算法 计算机视觉
图视觉模型崛起 | MobileViG同等精度比MobileNetv2快4倍,同等速度精度高4%!
图视觉模型崛起 | MobileViG同等精度比MobileNetv2快4倍,同等速度精度高4%!
334 0
|
小程序 JavaScript 前端开发
小程序实现滚动加载(懒加载)
小程序是一项很受欢迎的技术,随着其能力的不断增强,越来越多的人开始使用小程序来完成各种任务。当我面面临一个页面有非常多的数据时,该如何处理呢,显然一次性全部加载完,会非常消耗性能的,为了解决这些问题从而出现了一种叫滚动加载的数据处理方式,也被称为“无限滚动”或“懒加载”,它可以使你的页面在不刷新的情况下连续加载更多数据。在本文中,我们将讨论如何在小程序中实现滚动加载。
650 0
|
Linux 网络性能优化 C++
Linux UDP编程:深入探索无连接通信的实现与应用
在Linux操作系统中,UDP(用户数据报协议)是一种无连接的传输协议,适用于那些对数据传输延迟要求较高、但可靠性要求相对较低的场景。本文将深入探索Linux UDP编程的实现原理与应用,介绍UDP的工作机制、编程接口以及如何在Linux环境下编写UDP程序。
1109 0
|
编解码 算法 数据可视化
照片转视频,像航拍一样丝滑,NeRF原班人马打造Zip-NeRF(2)
照片转视频,像航拍一样丝滑,NeRF原班人马打造Zip-NeRF
525 0