首先lock和Minitor有什么区别呢?
其实lock在IL代码中会被翻译成Monitor。也就是Monitor.Enter(obj)和Monitor.Exit(obj).
lock(obj)
{
}
等价为:
try
{
Monitor.Enter(obj)
}
catch()
{}
finally
{
Monitor.Exit(obj)
}
所以lock能做的,Monitor肯定能做,Monitor能做的,lock不一定能做。那么Monitor额外的功能呢?
1:Monitor.TryEnter(obj,timespan)----timeout之后,就不执行这段代码了。lock可是一直会死等的。
2:还有Monitor.Wait()和Monitor.Pulse()。在lock代码里面如果调用了Monitor.Wait(),会放弃对资源的所有权,让别的线程lock进来。然后别的线程代码里Pulse一下(让原线程进入到等待队列),然后在Wait一下释放资源,这样原线程的就可以继续执行了(代码还堵塞在wait那句话呢)。
也就是说,必须两个或多个线程共同调用Wait和Pulse,把资源的所有权抛来抛去,才不会死锁。
和AutoEvent相似是处理同步关系的,但是AutoEvent是跨进程的,而Monitor是针对线程的。
以下是MSDN的代码示例,调试起来很容易看出来两个函数的作用了,因为尽管是多线程程序,但是是同步操作,所以代码始终是单步执行的。
using System;
using System.Threading;
using System.Collections;
namespace MonitorCS1
{
class MonitorSample
{
const int MAX_LOOP_TIME = 100;
Queue m_smplQueue;
public MonitorSample()
{
m_smplQueue = new Queue();
}
public void FirstThread()
{
int counter = 0;
lock (m_smplQueue)
{
while (counter < MAX_LOOP_TIME)
{
//Wait, if the queue is busy.
Monitor.Wait(m_smplQueue);
//Push one element.
m_smplQueue.Enqueue(counter);
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
counter++;
}
int i = 0;
}
}
public void SecondThread()
{
lock (m_smplQueue)
{
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
//Wait in the loop, while the queue is busy.
//Exit on the time-out when the first thread stops.
while (Monitor.Wait(m_smplQueue, 50000))
{
//Pop the first element.
int counter = (int)m_smplQueue.Dequeue();
//Print the first element.
Console.WriteLine(counter.ToString());
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
}
}
}
//Return the number of queue elements.
public int GetQueueCount()
{
return m_smplQueue.Count;
}
static void Main(string[] args)
{
//Create the MonitorSample object.
MonitorSample test = new MonitorSample();
//Create the first thread.
Thread tFirst = new Thread(new ThreadStart(test.FirstThread));
//Create the second thread.
Thread tSecond = new Thread(new ThreadStart(test.SecondThread));
//Start threads.
tFirst.Start();
tSecond.Start();
//wait to the end of the two threads
tFirst.Join();
tSecond.Join();
//Print the number of queue elements.
Console.WriteLine("Queue Count = " + test.GetQueueCount().ToString());
}
}
}