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

来源:互联网 发布:一座城池知乎 编辑:程序博客网 时间:2024/06/07 14:30

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,

本文转自:http://www.cnblogs.com/cappuccino/archive/2011/01/06/1927659.html


0 0
原创粉丝点击