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


    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,



  • 相关阅读:
    RocketMQ源码 — 十、 RocketMQ顺序消息
    RocketMQ源码 — 九、 RocketMQ延时消息
    RocketMQ源码 — 八、 RocketMQ消息重试
    HDU3439 Sequence
    Cipolla算法学习小记
    BZOJ2286: [Sdoi2011]消耗战
    BZOJ4873 寿司餐厅
    BZOJ1718 [Usaco2006 Jan] Redundant Paths 分离的路径
    BZOJ1123 [POI2008]BLO
    BZOJ3996 TJOI2015线性代数
  • 原文地址:https://www.cnblogs.com/cappuccino/p/1927659.html
Copyright © 2020-2023  润新知