Lock VS Monitor
介紹
介紹
對開發人員來說,處理關鍵代碼部分的多線程應用程序是非常重要的。
Monitor和lock是c#語言中多線程應用程序中提供線程安全的方法(lock關鍵字的本質就是對Monitor的封裝)。兩者都提供了一種機制來確保只有一個線程同時執行代碼,以避免代碼功能被其他線程中斷
鎖
c#中 Lock關鍵字確保一個線程同時執行一段代碼。lock關鍵字確保一個線程不進入代碼的鎖定區,而另一個線程在鎖定區內。
Lock關鍵字是Monitor的“快捷方式”。
namespace Monitor_Lock { class Program { static readonly object _object = new object(); static void TestLock() { lock (_object) { Thread.Sleep(100); Console.WriteLine(Environment.TickCount); } } static void Main(string[] args) { for (int i = 0; i < 10; i++) { ThreadStart start = new ThreadStart(TestLock); new Thread(start).Start(); } Console.ReadLine(); } } }輸出:
這里我們看到一個靜態方法“TestLock”,它在對象上使用lock語句。在新線程上多次調用TestLock方法時,每次調用該方法都會訪問該鎖的對象是否釋放。
Main方法創建十個新線程,然后在每個線程上開始調用。方法TestLock被調用十次,但是Environment.TickCount計數器顯示受保護的方法區域是按順序執行的,大約相隔100毫秒。
如果另一個線程試圖進入一個鎖定的代碼,它將等待,阻塞,直到對象被釋放。
lock關鍵字通過獲取給定對象的互斥鎖,將語句塊標記為一個臨界段,執行語句,然后釋放鎖,
Monitor
Monitor提供了一種同步對象訪問的機制。它可以通過獲取一個重要的鎖來實現,這樣一次只有一個線程可以進入給定的代碼段。Monitor與lock沒有什么不同,但是Monitor類對試圖訪問相同代碼鎖的各個線程的同步提供了更多的控制。
使用Monitor可以確保不允許任何其他線程訪問鎖所有者正在執行的應用程序代碼段,除非其他線程使用不同的鎖定對象執行代碼。
Monitor類有以下方法通過獲取和釋放鎖來同步訪問代碼的某個區域
| Enter(Object) | 在指定對象上獲取排他鎖。 |
| Enter(Object, Boolean) | 獲取指定對象上的排他鎖,并自動設置一個值,指示是否獲取了該鎖。 |
| Exit(Object) | 釋放指定對象上的排他鎖。 |
| IsEntered(Object) | 確定當前線程是否保留指定對象鎖。 |
| Pulse(Object) | 通知等待隊列中的線程鎖定對象狀態的更改。 |
| PulseAll(Object) | 通知所有的等待線程對象狀態的更改。 |
| TryEnter(Object, TimeSpan, Boolean) | 在指定的一段時間內嘗試獲取指定對象上的排他鎖,并自動設置一個值,指示是否獲得了該鎖。 |
| TryEnter(Object, Int32, Boolean) | 在指定的毫秒數內嘗試獲取指定對象上的排他鎖,并自動設置一個值,指示是否獲取了該鎖。 |
| TryEnter(Object, TimeSpan) | 在指定的時間內嘗試獲取指定對象上的排他鎖。 |
| TryEnter(Object, Boolean) | 嘗試獲取指定對象上的排他鎖,并自動設置一個值,指示是否獲取了該鎖。 |
| TryEnter(Object) | 嘗試獲取指定對象的排他鎖。 |
| TryEnter(Object, Int32) | 在指定的毫秒數內嘗試獲取指定對象上的排他鎖。 |
| Wait(Object, Int32, Boolean) | 釋放對象上的鎖并阻止當前線程,直到它重新獲取該鎖。?如果已用指定的超時時間間隔,則線程進入就緒隊列。?此方法還指定是否在等待之前退出上下文的同步域(如果處于同步上下文中的話)然后重新獲取該同步域。 |
| Wait(Object) | 釋放對象上的鎖并阻止當前線程,直到它重新獲取該鎖。 |
| Wait(Object, Int32) | 釋放對象上的鎖并阻止當前線程,直到它重新獲取該鎖。?如果已用指定的超時時間間隔,則線程進入就緒隊列。 |
| Wait(Object, TimeSpan) | 釋放對象上的鎖并阻止當前線程,直到它重新獲取該鎖。?如果已用指定的超時時間間隔,則線程進入就緒隊列。 |
| Wait(Object, TimeSpan, Boolean) | 釋放對象上的鎖并阻止當前線程,直到它重新獲取該鎖。?如果已用指定的超時時間間隔,則線程進入就緒隊列。?可以在等待之前退出同步上下文的同步域,隨后重新獲取該域。 |
Monitor鎖定對象(即引用類型),而不是值類型。雖然您可以傳遞一個值類型來進入和退出,但是對于每個調用,它都是單獨裝箱的。
Wait在鎖被持有并等待被通知時釋放鎖。當Wait被通知時,它返回并再次獲得鎖。Pulse和PulseAll都為等待隊列中的下一個線程的開始發出信號。
下面是使用Monitor的語法。
try { int x = 1; Monitor.Enter(x); try { // Code that needs to be protected by the monitor. } finally { Monitor.Exit(x); } } catch (SynchronizationLockException SyncEx) { Console.WriteLine("A SynchronizationLockException occurred. Message:"); Console.WriteLine(SyncEx.Message); }簡單例子:
輸出:
在c# 4.0中,Monitor.Enter(_object,ref _lockTaken)重載函數獲取一個獨占鎖和指定的對象,并自動設置一個值,該值指示鎖是否被獲取。
與lock等價的Monitor實現
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }結論
Monitor類是一個靜態類,不能創建它的實例。
Monitor類對象使用 Monitor.TryEnter, and Monitor.Exit 方法。一旦鎖定了代碼區域,就可以使用 Monitor.Wait, Monitor.Pulse, and Monitor.PulseAll 等方法。
Lock和monitor在多線程中基本上用于相同的目的,Monitor的不同之處在于,當我們希望對運行特定代碼段的多個線程的同步進行更多控制時更有效
總結
以上是生活随笔為你收集整理的Lock VS Monitor的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 荐读|属性与可直接访问的数据成员之间应该
- 下一篇: 程序员修神之路--做好分库分表其实很难之