日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【转】细说.NET中的多线程 (四 使用锁进行同步)

發布時間:2023/12/10 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】细说.NET中的多线程 (四 使用锁进行同步) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

通過鎖來實現同步

排它鎖主要用來保證,在一段時間內,只有一個線程可以訪問某一段代碼。兩種主要類型的排它鎖是lock和Mutex。Lock和Mutex相比構造起來更方便,運行的也更快。但是Mutex可以在同一個機器上的不同進程使用

Monitor.Enter和Monitor.Exit

C#中的lock關鍵字,實際上是Monitor.Enter,Monitor.Exist的一個簡寫。在.NET 1.0,2.0,3.0 版本的c#中,lock會被編譯成如下代碼:

1 2 3 4 5 6 7 Monitor.Enter(_locker); try { ????if?(_val2 != 0) Console.WriteLine(_val1 / _val2); ????_val2 = 0; } finally?{ Monitor.Exit(_locker); }

如果你沒有調用Monitor.Enter而直接調用Monitor.Exit會引發異常。

LockTaken版本:

想象一下上面這段代碼,如果再Monitor.Enter之后,try之前,線程出現了異常(比如被終止),在這種情況下,finally中的Exit方法就永遠不會被執行,也就導致了這個鎖不會被釋放。為了避免這種情況,CLR 4.0的設計者重載了Monitor.Enter方法:

1 public?static?void?Enter (object?obj,?ref?bool?lockTaken);

?

如果當前線程由于某些異常導致鎖沒有被獲取到,lockTake值會為false,因此在CLR 4.0中,lock會被解釋成如下代碼:

1 2 3 4 5 6 7 8 9 10 bool?lockTaken =?false; try { ? ????Monitor.Enter(_locker,?ref?lockTaken); ? ????// Do your stuff... } ? finally?{?if?(lockTaken) Monitor.Exit(_locker); }

TryEnter

Monitor也提供了了一個TryEnter方法,允許你設置一個超時時間,避免當前線程長時間獲取不到鎖而一直等待。

選擇正確的同步對象

你需要選擇一個對所有線程都可見的對象進行lock(obj)來確保程序能夠按照你的意圖執行。如果你不了解C#語言中的某些特性,lock可能不會按照你 期望來執行。

  • 由于字符串的駐留機制,lock("string")不是一個好的選擇
  • Lock一個值類型不是一個好的選擇
  • Lock(typeof(..))不是一個好的選擇,因為System.Type的特性
  • 什么時候使用lock

    一個基本的規則,你需要對任意的寫操作,或者可修改的字段進行lock。即使是一個賦值操作,或者累加操作,你也不能假設他是線程安全的。

    例如下面代碼不是線程安全的:

    1 2 3 4 5 6 class?ThreadUnsafe { ????static?int?_x; ????static?void?Increment() { _x++; } ????static?void?Assign() { _x = 123; } }

    ?

    你需要這樣寫:

    1 2 3 4 5 6 7 8 class?ThreadSafe { ????static?readonly?object?_locker =?new?object(); ????static?int?_x; ? ????static?void?Increment() {?lock?(_locker) _x++; } ????static?void?Assign() {?lock?(_locker) _x = 123; } }

    如果你看過一些BCL類庫里面的實現,你可以能會發現,某些情況下會使用InterLocked類,而不是lock,我們會在后面介紹。

    關于嵌套鎖或者reentrant

    你在閱讀一些文檔的時候,有的文檔可能會說lock或者Monitor.Enter是reentrant(可重入的),那么我們如何理解reentrant呢?

    想象下以下代碼:

    1 2 3 4 5 6 lock?(locker) ????lock?(locker) ????????lock?(locker) ????????{ ????????????// Do something... ????????}

    ?

    或者是:

    1 2 3 Monitor.Enter(locker); Monitor.Enter(locker); Monitor.Enter(locker); // Do something... Monitor.Exit(locker); Monitor.Exit(locker); Monitor.Exit(locker);

    這種情況下,只有在最后一個exit執行后,或者執行了相應次數的Exit后,locker才是可獲取的狀態。

    Mutex

    Mutex像c#中的lock一樣,但是在不同的進程中仍然可以使用。換句話說,Mutex是一個計算機級別的鎖。因此獲取這樣一個鎖要比Monitor慢很多。

    示例代碼:

    ?

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 using?System; using?System.Threading.Tasks; using?System.Threading; ? namespace?MultiThreadTest { ????class?OneAtATimePlease ????{ ????????static?void?Main() ????????{ ????????????// Naming a Mutex makes it available computer-wide. Use a name that's ????????????// unique to your company and application (e.g., include your URL). ? ????????????using?(var?mutex =?new?Mutex(false,?"oreilly.com OneAtATimeDemo")) ????????????{ ????????????????// Wait a few seconds if contended, in case another instance ????????????????// of the program is still in the process of shutting down. ? ????????????????if?(!mutex.WaitOne(TimeSpan.FromSeconds(3),?false)) ????????????????{ ????????????????????Console.WriteLine("Another app instance is running. Bye!"); ????????????????????return; ????????????????} ????????????????RunProgram(); ????????????} ????????} ? ????????static?void?RunProgram() ????????{ ????????????Console.WriteLine("Running. Press Enter to exit"); ????????????Console.ReadLine(); ????????} ????} }

    Semaphore

    Monitor和Mutex都是排他鎖,Semaphore我們常用的另外一種非排他的鎖。

    我們用它來實現這樣一個例子:一個酒吧,最多能容納3人,如果客滿則需要等待,有客人離開,等待的人隨時可以進來。

    示例代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using?System; using?System.Threading; ? class?TheClub??????// No door lists! { ????static?Semaphore _sem =?new?Semaphore(3, 3);????// Capacity of 3 ? ????static?void?Main() ????{ ????????for?(int?i = 1; i <= 5; i++)?new?Thread(Enter).Start(i); ? ????????Console.ReadLine(); ????} ? ????static?void?Enter(object?id) ????{ ????????Console.WriteLine(id +?" wants to enter"); ????????_sem.WaitOne(); ????????Console.WriteLine(id +?" is in!");???????????// Only three threads ????????Thread.Sleep(1000 * (int)id);???????????????// can be here at ????????Console.WriteLine(id +?" is leaving");???????// a time. ????????_sem.Release(); ????} }

    ?

    使用Semaphore需要調用者來控制訪問資源,調用WaitOne來獲取資源,通過Release來釋放資源。開發者有責任確保資源能夠正確釋放。

    Semaphore在限制同步訪問的時候非常有用,它不會像Monitor或者Mutex那樣當一個線程訪問某些資源時,其它所有線程都需要等,而是設置一個緩沖區,允許最多多少個線程同時進行訪問。

    Semaphore也可以像Mutex一樣,跨進程進行同步。

    ?

    本節主要總結了使用鎖進行同步,下一節將總結使用信號量進行同步。?????

    總結

    以上是生活随笔為你收集整理的【转】细说.NET中的多线程 (四 使用锁进行同步)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。