歡迎您光臨本站 註冊首頁

一篇文章帶你輕鬆瞭解C# Lock關鍵字

←手機掃碼閱讀     lousu-xi @ 2020-06-15 , reply:0

  相信絕大多數.NET玩家和我一樣,常常使用Timer這個對象,而在WPF中使用DispatcherTimer的人也是很多,DispatcherTimer是在UI線程跑的。我們的程序中大多數都會充斥很多Timer,可以理解它是一個線程,它繼承自 System.Windows.Threading 。

  程序中也許會有一些靜態變量或是單例模式的對象來讓不同的頁面進行交互,但也就是這樣讓每個線程之間打架提供了基礎。因為資源是單獨的,就像是腳踩兩隻船的人,必定會翻車。例如一個List集合,你在一個線程中對它進行了操作,在同步瞬間的另線程中,如果不對它謹慎處理,就會造成 “集合已修改;可能無法執行枚舉操作”。當然我們說的不是關於集合的相關問題,而是關於資源分配的,當然在資源搶奪上,是在耗時的線程中才會出現的,例如下面的這張圖。

  這種耗時的操作,並且在同步線程中,沒有對線程進行封裝,很容易造成資源搶奪問題,假如Object是個集合,我在中間把它改了,下一秒的其它線程對它進行髒讀了,就會產生錯誤,我們可以通過Lock關鍵字。

  首先在Microsoft文檔中對Lock的說明是,lock 關鍵字可以用來確保代碼塊完成運行,而不會被其他線程中斷。這是通過在代碼塊運行期間為給定對象獲取互斥鎖來實現的。

  不過我們需要注意的是Lock本質上Monitor.Enter,Monitor.Enter會使值類型裝箱,每次Lock的是裝箱後的對象。Lock其實是類似編譯器的語法糖,因此編譯器直接限制住不能lock值類型,為啥呢,你仔細想想,每次裝箱後都是不同的對象,我怎麼判斷? object.ReferenceEquals 每次都是false...還有就是千萬不要Lock 字符串,簡單來說Lock字符串之後,只要是你以後有字符串匹配和你Lock裡的內容有一樣的,那個該字符串也會被鎖定,相當於死鎖了。

  Lock和Monitor的區別不是很大,具體看以下代碼。

  private static object obj = new object();    public void LockSomething()    {     lock (obj)     {      dosomething();     }    }    public void MonitorSomeThing()    {      Monitor.Enter(obj);      dosomething();      Monitor.Exit(obj);    }    public void dosomething()    {     //做具體的事情    }

 

   lock和Monitor是.NET用一個特殊結構實現的,Monitor對象是完全託管的、完全可移植的,並且在操作系統資源要求方面可能更為有效,同步速度較快,但不能跨進程同步。主要作用是鎖定臨界區,使臨界區代碼只能被獲得鎖的線程執行。Monitor.Wait和Monitor.Pulse用於線程同步,類似信號操作,個人感覺使用比較複雜,容易造成死鎖。

  lock就是封裝了Monitor.Enter和Monitor.Exit方法其實非常不難理解,只要確定Lock在啥時候用,該怎麼用就可以了,總結一句話。經常會應用於防止多線程操作導致公用變量值出現不確定的異常,用於確保操作的安全性。



[lousu-xi ] 一篇文章帶你輕鬆瞭解C# Lock關鍵字已經有233次圍觀

http://coctec.com/docs/c/language/show-post-238612.html