.NET提供了System.Threading.Monitor类允许同一进城中的线程实现同步,是一种更快速、更轻量级的锁机制。可以使用该类来保护对某些变量的访问,或对某些一次只能在一个线程中执行的代码设置访问权限。
使用实例(片段代码):
readonly object theLock=new object(); int num=0; #其他代码... Monitor.Enter(theLock); try{ ++num; }finally{ Monitor.Exit(theLock); }
- Monitor与lock
对以上代码的解读:- Monitor.Enter(theLock)获得theLock对象锁;Monitor.Exit(theLock)释放theLock对象锁;
- 我们将所有对num变量的访问以对象锁的形式房在临界区,在每次访问前,访问者必须获得theLock对象实例的锁。theLock字段类型是 Object类型,它的实际类型无关紧要,但必须是引用类型即对象的实例,而不是值类型。为了安全起见,建议标记成readonly,以免theLock 被复制而造成混乱。
- 上述代码不够简洁,使用try/finally,而且一旦漏掉Monitor.Exit将会发生可怕的混乱。就此问题C#设计者引用了lock关键字,lock关键字代替了Monitor.Enter和Monitor.Exit,上述代码可简写为:
readonly object theLock=new object(); int num=0; #其他代码... lock(theLock){ ++num; }
- 通知与等待
- Monitor管理着两个线程队列:就绪队列(ready队列)和等待队列(waiting队列)。
- ready队列保存的是准备获取锁的线程,就是说,如果某个线程(几座线程A)执行了Monitor.Wait(),那么ready队列中的第一个线程就会获得锁,开始运行;同时线程A自动进入waiting队列中的队尾进行排队。
- waiting队列保存的是正在等待锁对象状态变化通知的线程,就是说如果某个线程执行了Moniotr.Pulse(),那么waiting队列中的对头线程就进入ready队列中。
- 简单地说即是当前线程执行Monitor.Wait(),当前线程进入waiting队列并取ready队列对头线程运行;执行Monitor.Pulse把waiting队列的对头线程调入ready队列。