监视器
Monitor 对象通过使用 Monitor.Enter、Monitor.TryEnter 和 Monitor.Exit 方法对特定对象进行加锁和解锁来提供同步访问代码区域的功能。 对代码区域加锁之后,可以使用 Monitor.Wait、Monitor.Pulse 和 Monitor.PulseAll 方法。 Wait 在其暂停并等待通知的情况下解锁。 当 Wait 收到通知时,会返回并重新加锁。 Pulse 和PulseAll 都发送信号以继续执行等待队列中的下一个线程。
lock语句使用Monitor.Enter
获取锁,使用Monitor.Exit
释放锁。使用lock的优点在于块中的所有内容包含在Try语句中,Try语句有一个finally块用于保证锁得以释放。
Monitor
将锁定对象(引用类型)而非值类型。如果将值类型传递给Enter和Exit时,它会针对每个调用分别装箱。 由于每个调用都创建一个单独的对象,所以 Enter 从不拦截,此外,传递给 Exit 的对象不同于传递给 Enter 的对象,所以 Monitor 将引发 SynchronizationLockException
虽然您可以在调用 Enter 和 Exit 之前装箱值类型变量,并将相同的装箱对象同时传递给两个方法,但是这样做没有任何好处。 对变量的更改不能在装箱的变量中体现出来,也没有办法更改已装箱的变量的值。
一个Demo:
namespace MyConsole2
{
class Program
{
static Int32 numAsyncOps = 5;
static AutoResetEvent asyncOpsAreDone = new AutoResetEvent(false);
static SyncResource SyncRes = new SyncResource();
static UnSyncResource UnSyncRes = new UnSyncResource();
static void Main(string[] args)
{
for (Int32 threadNum = 0; threadNum < 5; threadNum++)
{
//ThreadPool.QueueUserWorkItem(new WaitCallback(SyncUpdateResource), threadNum);
ThreadPool.QueueUserWorkItem(new WaitCallback(UnSyncUpdateResource), threadNum);
}
asyncOpsAreDone.WaitOne();//阻塞当前现在,直到WaitHandler收到信号
Console.WriteLine("
All synchronized operations have completed.
");
Console.ReadLine();
}
static void SyncUpdateResource(Object state)
{
// This calls the internal synchronized method, passing
// a thread number.
SyncRes.Access((Int32)state);
// Count down the number of methods that the threads have called.
// This must be synchronized, however; you cannot know which thread
// will access the value **before** another thread's incremented
// value has been stored into the variable.
if (Interlocked.Decrement(ref numAsyncOps) == 0)
{
// Announce to Main that in fact all thread calls are done.
asyncOpsAreDone.Set();//将事件状态设置为终止状态
}
}
static void UnSyncUpdateResource(Object state)
{
// This calls the unsynchronized method, passing a thread number.
UnSyncRes.Access((Int32)state);
// Count down the number of methods that the threads have called.
// This must be synchronized, however; you cannot know which thread
// will access the value **before** another thread's incremented
// value has been stored into the variable.
if (Interlocked.Decrement(ref numAsyncOps) == 0)
{
// Announce to Main that in fact all thread calls are done.
asyncOpsAreDone.Set();
}
}
}
class SyncResource
{
public void Access(Int32 threadNum)
{
// Uses Monitor class to enforce synchronization.
lock (this)
{
// Synchronized: Despite the next conditional, each thread
// waits on its predecessor.
if (threadNum % 2 == 0)
{
Thread.Sleep(2000);
}
Console.WriteLine("Start Synched Resource access (Thread={0})", threadNum);
Thread.Sleep(200);
Console.WriteLine("Stop Synched Resource access (Thread={0})", threadNum);
}
}
}
// Without the lock, the method is called in the order in which threads reach it.
class UnSyncResource
{
public void Access(Int32 threadNum)
{
// Does not use Monitor class to enforce synchronization.
// The next call throws the thread order.
if (threadNum % 2 == 0)
{
Thread.Sleep(2000);
}
Console.WriteLine("Start UnSynched Resource access (Thread={0})", threadNum);
Thread.Sleep(200);
Console.WriteLine("Stop UnSynched Resource access (Thread={0})", threadNum);
}
}
}