Lock 與Monitor 的用法與區別


1.lock的底層本身是Monitor來實現的,所以Monitor可以實現lock的所有功能

2.Monitor有TryEnter的功能,可以防止出現死鎖的問題,lock沒有。

3.Monitor.Enter(object)方法是獲取鎖,Monitor.Exit(object)方法是釋放鎖,這就是Monitor最常用的兩個方法,當然在使用過程中為了避免獲取鎖之后因為異常,致鎖無法釋放,所以需要在try{} catch(){}之后的finally{}結構體中釋放鎖(Monitor.Exit())。

4.Monitor的常用屬性和方法:

    Enter(Object) 在指定對象上獲取排他鎖。

    Exit(Object) 釋放指定對象上的排他鎖。

    IsEntered 確定當前線程是否保留指定對象鎖。

    Pulse 通知等待隊列中的線程鎖定對象狀態的更改。

    PulseAll 通知所有的等待線程對象狀態的更改。

    TryEnter(Object) 試圖獲取指定對象的排他鎖。

    TryEnter(Object, Boolean) 嘗試獲取指定對象上的排他鎖,並自動設置一個值,指示是否得到了該鎖。

    Wait(Object) 釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖。

5.Lock關鍵字實際上是一個語法糖,它將Monitor對象進行封裝,給object加上一個互斥鎖,A進程進入此代碼段時,會給object對象加上互斥鎖,此時其他B進程進入此代碼段時檢查object對象是否有鎖?如果有鎖則繼續等待A進程運行完該代碼段並且解鎖object對象之后,B進程才能夠獲取object對象為其加上鎖,訪問代碼段。

6.其實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額外的功能呢?


還有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());
        }
    }
}

參考
 http://blog.sina.com.cn/s/blog_57a829dd01010zyp.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM