异步编程之共享对象同步

当我使用实现异步编程时,大大的提高了,CUP利用率,让前端UI线程能够得到及时的响应.

但在我们使用时,必须要考虑到线程共享对象的同步问题,否则计算结果将不可控.所以,这里,根据自己的经验,对C#中用于解决线程同步问题简单的总结一下.

实现线程同有一下几种方式:

1.lock(Monitor的语法糖) 2.Monitor 3.AutoResetEvent 4.Interlocked(原子操作) 5.SpinLock 6.Semaphore 7.Mutex

下面直接上代码对几种实现方式的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            //初始化一个用户,出事账户金额10000元。
            //初始化10个任务,每次调用用户购物事件,扣取随机金额。
           
            var user = new User(10000);
            var tasks = new List<Task>();
            System.Random r = new Random();
            for (int i = 0; i < 10; i++)
            {
                var t = new Task(() =>
                {
                    user.Shopping(r.Next(1, 5000));
                });
                tasks.Add(t);
            }
            tasks.ForEach(t =>{t.Start();});

            Console.ReadKey();
        }


    }

    class User{

        //异步编程-控制并发
        //为保证一个公共对象,在同一时刻只有一个线程占有操作。
        //锁实现方式有多种 1.lock(Monitor的语法糖) 2.Monitor 3.AutoResetEvent 4.Interlocked(原子操作) 5.SpinLock 6.Semaphore 7.Mutex

        private AutoResetEvent autoResetEvent = new AutoResetEvent(true);
        private int interlocked = 0;
        private SpinLock spinLock = new SpinLock(false);
        private Semaphore semaphore = new Semaphore(0, 1);
        private Mutex mutex = new Mutex();

        private decimal Amount; //账户金额

        /// <summary>
        /// 构造函数,初始化账户金额
        /// </summary>
        /// <param name="amount"></param>
        public User(decimal amount)
        {
            this.Amount = amount;
        }

        /// <summary>
        /// 购物消费
        /// </summary>
        /// <param name="money"></param>
        public void Shopping(decimal money) {
            
            //1.lock示例(只能锁引用对象)
            lock (this){
                UpdateAmount(money);
            }

            //2.Monitor(只能锁引用对象)
            try{
                Monitor.Enter(this);//加锁
                UpdateAmount(money);
            }
            finally {
                Monitor.Exit(this);//释放锁
            }


            //3.AutoResetEvent
            //通知正在等待的线程已发生事件
            try
            {
                autoResetEvent.WaitOne();//加锁
                UpdateAmount(money);
            }
            finally {
                autoResetEvent.Set();//释放锁
            }

            //4.Interlocked (自旋锁)
            //为多个线程共享的变量提供原子操作。
            //
            try
            {
                while (1 == Interlocked.Exchange(ref interlocked, 1))
                {
                    //如果值为1,则一直自旋等待.
                }
                UpdateAmount(money);
            }
            finally
            {
                Interlocked.Exchange(ref interlocked, 0);
            }
           
            //5.SpinLock
            //提供一个相互排斥锁基元,在该基元中,尝试获取锁的线程将在重复检查的循环中等待,直至该锁变为可用为止.
            //锁定一个布尔类型对象,初始值必须为false
            bool spinLocker = false;
            try
            {
               
                spinLock.Enter(ref spinLocker);//加锁
                UpdateAmount(money);
            }
            finally
            {
                if(spinLocker)
                   spinLock.Exit();//释放锁
            }

            //6.Semaphore(信号)
            //限制可同时访问某一资源或资源池的线程数
            try
            {

                semaphore.WaitOne();//加锁
                UpdateAmount(money);
            }
            finally
            {
                semaphore.Release(1);//释放锁
            }

            //7.Mutex
            //可用于线程,还可用于进程间同步的同步基元。
            try
            {
                mutex.WaitOne();//加锁
                UpdateAmount(money);
            }
            finally
            {
                mutex.ReleaseMutex();//释放锁
            }
        }
        /// <summary>
        /// 更新账户
        /// </summary>
        /// <param name="money"></param>
        private void UpdateAmount(decimal money) {
            if (this.Amount < money)
            {
                //账户金额不足,显示账户金额。
                Console.WriteLine("本次消费:" + money + ",余额不足!当前余额:" + this.Amount);
            }
            else {
                //账户金额充足,更新账户金额,显示账户金额。
                Console.WriteLine(this.Amount + "-" + money + " = " + (this.Amount - money));
                this.Amount -= money;
            }
        }
    }
}

 

posted on 2018-12-06 13:26  潇潇@暮雨  阅读(171)  评论(0编辑  收藏  举报

导航