异步编程之共享对象同步
当我使用实现异步编程时,大大的提高了,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; } } } }