名称空间: System.threading
Monitor通过授予单线程对象锁来控制对象的访问。该类型对于多线程操作是安全的。
对象锁有提供限制访问代码块(临界区域)的能力。当一个线程拥有对象锁的时候,其他任何线程都不能获取该对象锁。使用Monitor 来确保不会允许其他任何线程访问由锁的所有者执行的应用程序代码块,除非另一个线程正在使用其他锁对象执行改代码。(注:使用Monitor锁定的对象是引用类型,不是值类型)
Monitor 的特点:
- 它根据需要于某个对象相关联;
- 它是未绑定的,可以从任何上下文中调用;
- 不能创建它的实例;
- 将为每个同步对象来维护以下信息
- 对当前持有锁的线程的引用
- 对就绪线程的引用,包含准备获取锁的线程
- 对等待队列的引用,包含正在等待锁定对象状态变化通知的线程
下表描述了访问同步对象的线程可以采取的操作:
Enter 和 TryEnter :获取对象锁,同样会标记临界区的开头;任何其他线程都不能访问临界区,除非其他线程用其他锁定对象执行临界区的指令。(晕,越看越糊涂了)
Wait :释放对象上的锁,以便其他线程锁定和访问该对象,在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的变更。
Pulse 和 PulseAll :向一个或多个等待线程发送信号,该信号通知对定对象的状态已经更改,并锁的所有者准备释放该锁。等待线程被放置在对象的就绪队列中以便可以最后接收到对象锁。一旦线程有了新锁,它可以检查对象的新状态以查看是否达到所需状态。
Exit :释放对象上的锁,还可以标记受锁对象保护的临界区的结尾。
使用 Enter 和 Exit 方法标记临界区的开头和结尾。如果临界区是一个连续指令集,则由 Enter 方法获取的锁将保证只有一个线程可以使用锁定对象执行所包含的代码。在这种情况下,建议您将这些指令放在 try 块中,并将 Exit 指令放在 finally 块中。此功能通常用于同步对类的静态或实例方法的访问。如果实例方法需要同步线程访问,则它将使用当前实例作为要锁定的对象调用 Enter 和对应的 Exit 方法。由于只能有一个线程持有当前实例上的锁,因此该方法一次只能由一个线程来执行。静态方法是使用当前实例的 Type 作为锁定对象以类似的方式来保护的。Enter 和 Exit 方法提供的功能与 C# lock 语句(在 Visual Basic 中为 SyncLock)提供的功能相同,区别在于 lock 和 SyncLock 以 try…finally 块(在 Visual Basic 中为 Try…Finally)来包装 Exit 方法,以确保释放监视器。
如果临界区跨越整个方法,则可以通过将 System.Runtime.CompilerServices.MethodImplAttribute 放置在方法上并在 MethodImplAttribute 的构造函数中指定 Synchronized 值来实现上述锁定功能。使用该属性后就不需要 Enter 和 Exit 语句了。请注意,该属性将使当前线程持有锁,直到方法返回;如果可以更早释放锁,则使用 Monitor 类或 C#lock 语句而不是该属性。
尽管锁定和释放给定对象的 Enter 和 Exit 语句可以跨越成员或类的边界或同时跨越两者的边界,但并不推荐这样做。
当选择要同步的对象时,应只锁定私有或内部对象。锁定外部对象可能导致死锁,这是因为不相关的代码可能会出于不同的目的而选择锁定相同的对象。