本文用經典的生產者消費者的例子,說明Mnitor對象的用法。實現的目標是:
生產者生產一個資料,然後消費者開始消費,消費完成後生產者繼續生產,迴圈10次後結束。
下面是代碼:
namespace ConsoleTest
{
/// <summary>
/// 生產者消費者例子
/// </summary>
public class Producer_Consumer
{
/// <summary>
/// 生產者生產資料
/// </summary>
private void produce()
{
for (int i = 0; i < 10;i++ )
{
try
{
Monitor.Enter(_locker); //在調用Wait方法前必須擷取對象的鎖
{
Monitor.Wait(_locker); //阻塞當前線程,釋放鎖,進入等待狀態
Thread.Sleep(500); //此處是為了讓程式的執行過程更清楚
_count++;
Console.WriteLine("生產者: " + _count);
Monitor.Pulse(_locker); //通知等待擷取鎖(即調用Wait方法的線程)的消費者線程進入就緒狀態
}
}
finally
{
Monitor.Exit(_locker); //釋放鎖
}
}
}
/// <summary>
/// 消費者消費資料
/// </summary>
private void consume()
{
try
{
Monitor.Enter(_locker); //在調用Pulse方法前必須擷取對象的鎖
{
Monitor.Pulse(_locker); //此處不加這句代碼會造成死結
while (Monitor.Wait(_locker)) //迴圈等待生產者線程生產資料完成
{
Thread.Sleep(500);
Console.WriteLine("消費者:" + _count);
Monitor.Pulse(_locker); //消費完成後,通知生產者繼續生產
if (_count == 10)
{
Console.ReadLine();
return; //消費完10個資料後程式退出
}
}
}
}
finally
{
Monitor.Exit(_locker);//釋放鎖
}
}
public void Test()
{
Thread thread1 = new Thread(produce);
Thread thread2 = new Thread(consume);
thread1.Start();
thread2.Start();
}
private int _count;
private object _locker = new object();
}
}
代碼中有幾個地方需要注意:
1、Monitor.Enter(object)方法是擷取鎖,Monitor.Exit(object)方法是釋放鎖,為了避免在擷取鎖後發
生異常,導致鎖無法釋放,所以要在finally塊中釋放鎖。經常用的lock(object){}其實是用如下方式實現的:
try{
Monitor.Enter(object);
//do something
}
finally{
Monitor.Exit(object);
}
2、Monitor.Pluse(object)調用後,程式不會立即轉向Minitor.Wait(object)執行,
它只是讓Wait的線程進入就緒狀態,獲得執行的可能性。