【C#進階系列】29 混合線程同步構造

来源:http://www.cnblogs.com/vvjiang/archive/2016/05/31/5548099.html
-Advertisement-
Play Games

上一章講了基元線程同步構造,而其它的線程同步構造都是基於這些基元線程同步構造的,並且一般都合併了用戶模式和內核模式構造,我們稱之為混合線程同步構造。 在沒有線程競爭時,混合線程提供了基於用戶模式構造所具備的性能優勢,而多個線程競爭一個構造時,混合線程通過基元內核模式的構造來提供不“自旋”的優勢。 那 ...


上一章講了基元線程同步構造,而其它的線程同步構造都是基於這些基元線程同步構造的,並且一般都合併了用戶模式和內核模式構造,我們稱之為混合線程同步構造。

在沒有線程競爭時,混合線程提供了基於用戶模式構造所具備的性能優勢,而多個線程競爭一個構造時,混合線程通過基元內核模式的構造來提供不“自旋”的優勢。

那麼接下來就是個簡單的混合線程同步構造的例子,可與上一章最後的那些例子相比較:

   public class SimpleHybridLock : IDisposable {
        private Int32 m_waiters = 0;

        private AutoResetEvent m_waiterlock = new AutoResetEvent(false);//註意這裡是false

        public void Enter() {
            if (Interlocked.Increment(ref m_waiters)==1) {
                return;
            }
            m_waiterlock.WaitOne();
        }
        public void Leave() {
            if (Interlocked.Decrement(ref m_waiters) == 0) {
                return;
            }
            m_waiterlock.Set();
        }
        public void Dispose() {
            m_waiterlock.Dispose();
        }
    }

上面的例子學了上一張後看起來感覺很簡單就不講解了,只是一個簡單的,將Interlocked這種互鎖構造和自動重置事件構造AutoResetEvent 結合起來的,混合線程同步構造的例子。

上面混合鎖可以去加入自旋,當超過一定的自旋次數時再進行阻塞。也可以去加入互斥體的遞歸玩法,總之這個東西充滿了無限的可能。

.NET 框架類庫中的混合構造

總體而言,實際上就是對上面那個簡單例子的擴展,它們的目的都是為了使線程能儘可能不去進入內核模式,並且減少線程競爭時自旋的性能影響。

  • ManualResetEventSlim類和SemaphoreSlim類
    • 翻譯過來就是手工重置事件簡化構造和信號量簡化構造
    • 發生第一次競爭時才進行內核模式構造,否則為用戶模式構造
    • 可傳遞超時值和CancellationToken,也就是取消啦,信號量那個還能進行非同步等待。
  • Monitor類和同步塊
    • Monitor類是最常用的,支持遞歸,線程所有權和互斥
    • 然而這個類存在一些問題,容易引發BUG。因為它是一個靜態類,它的正確玩法在一定程度上和其它同步構造有所區別。
    • 堆中的每個對象都可以關聯一個叫同步塊的數據結構,它為內核對象,且擁有線程ID,遞歸計數,等待線程計數。而Monitor類的操作就涉及到這些同步塊的欄位。
    • 每個對象都有一個同步塊索引,而同步塊實際上是在CLR初始化的時候就創建的一個同步塊數組中。
    • 一個對象在構造時它的同步塊索引為-1,就是沒有關聯任何同步塊。而調用Monitor.Enter後CLR在同步塊數組中找到個空白同步塊,並設置對象的同步塊索引,讓它引用該同步塊。Exit當然就是取消關聯。
    • Monitor.Enter會傳一個對象進去,這個對象必須為所在函數的類的私有對象,而不能傳所在對象本身,這回讓這個鎖變成公共的。這樣就會引發很多問題。所以最好的方法就是傳遞一個私有的只讀對象。
    • 永遠不要講String,值類型和類型對象傳給Monitor.Enter。
    • 而C#有一個lock關鍵字提供的簡化語法就是基於Monitor的。而且其相當於在一個try finally結構上使用。首先不利於性能,其次還可能造成線程訪問損壞的狀態。所以作者建議杜絕使用lock語法。
    • LockToken變數預設false,只有在Enter調用後才為true,要是在Enter調用前Exit,可以考慮判斷LockToken,從而避免錯誤的Exit。
  • ReaderWriterLockSlim類
    • 它的特點:
      • 一個線程向數據寫入時,請求訪問的其他所有線程都被阻塞
      • 一個線程從數據讀取時,請求讀取的其它線程允許繼續執行,但請求寫入的線程仍被阻塞。
      • 向線程寫入的線程結束後,要麼解除一個寫入線程的阻塞,使它能向數據寫入,要麼解除所有讀取線程的阻塞,使它們能併發讀取數據。如果沒有線程被阻塞,鎖就進入可以自由使用的狀態,可供下一個reader或writer線程獲取。
      • 從數據讀取所有線程結束後,一個writer線程被解除阻塞,使它能向數據寫入。如果沒有線程被阻塞,鎖就進入可以自由使用的狀態,可供下一個reader或writer線程獲取。
    •  根據以上特點有EnterReadLock和EnterWriteLock兩種玩法,兩種玩法跟之前的那些例子都類似,只是效果不同,這裡就不舉例了。

雖然提供了這麼多同步構造,且玩法也很多。但是最重要的還是一點:能儘量避免就避免阻塞線程,否則應儘量使用Volatile和Interlocked方法,因為它們速度快,然而這兩個只能操作簡單類型。

一定要阻塞,就可以使用Monitor類,也可以用ReaderWriterLockSlim類,雖然比Monitor慢,但是允許多個線程併發進行,提升了總體性能,減少阻塞線程的幾率。

用System.Lazy類或者System.Threading.LazyInitializer類去替代雙檢索玩法。

一句話解決這個點:

Lazy<String> s=new Lazy<String>(()=>DateTime.Now.ToLongTimeString(),true);

調用的話就用s.Value,實際上就是封裝了雙檢索,有些地方加了些優化。目的就是延時載入。

非同步鎖

其實叫非同步的同步構造,因為一般的同步構造都是用阻塞線程或者自旋來完成,而非同步鎖的目的就是為了不阻塞來玩。

SemaphoreSlim類的WaitAsync方法就是這個思路,信號量玩法而已。

而reader-writer語義的玩法是ConcurrentExclusiveSchedulerPair類。(當沒有ConcurrentScheduler任務時,使用ExclusiveScheduler為獨占式運行。沒有ExclusiveScheduler運行時,ConcurrentScheduler調度的任務可同時進行)

併發集合類

FCL自帶四個線程安全的集合類,全在System.Collections.Concurrent(Concurrent為併發的意思)命名空間中定義。

它們是ConcurrentQueue,ConcurrentStack,ComcurrentDictionary和ConcurrentBag。

所有這些都是“非阻塞“的。(實際上在ConcurrentQueue,ConcurrentStack和ConcurrentBag為空的時候還要提取數據,那麼提取數據的這個線程就會被阻塞)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡介 死鎖的本質是一種僵持狀態,是多個主體對於資源的爭用而導致的。理解死鎖首先需要對死鎖所涉及的相關觀念有一個理解。 一些基礎知識 要理解SQL Server中的死鎖,更好的方式是通過類比從更大的面理解死鎖。比如說一個經典的例子就是汽車(主體)對於道路(資源)的徵用,如圖1所示。 圖1.對於死鎖的直 ...
  • 引導工具GRUB詳解 引導工具GRUB詳解 引導工具GRUB詳解 導讀 引導程式是駐留在硬碟第一個扇區(MPR、主引導記錄)的程式。GRUB是一個功能強大的多系統引導程式,專門處理Linux與其它操作系統共存的問題。下麵就由我介紹一下grub.conf文件里的具體內容及其含義。 使用一下命令可以查看 ...
  • 人們對決策樹的使用 決策樹常常被應用於數據挖掘之中,是最基礎的演算法之一,幾乎每一個學習過數據挖掘的朋友都知道決策樹。但還原決策樹本來的用途,它被用於一些決策或決定時,還是比較實用和直觀的。其樹型結構指導人們進行在面對某個決策時,先關註其中幾個最重要的方向,這幾方向定下來後,再細分下去。近年來泳道路, ...
  • 公司產品中一直是採用 flash 實現文件上傳功能,但用戶的需求多了以後遇到了越來越多難以解決的問題,最後試著用碩正提供的freeform、小型頁面控制項來解決。 碩正文件上傳的實現途徑有3、4種,由於公司產品發佈的需要,就選擇了其中的 httpPost 方案,其它的象 ftp、Http put儘管也 ...
  • MSDN中的描述: Visual Studio 項目對程式的發佈和調試版本分別有單獨的配置。顧名思義,生成調試版本的目的是用於調試,而生成發佈版本的目的是用於版本的最終分發。 如果在 Visual Studio 中創建程式,Visual Studio 將自動創建這些配置並設置適當的預設選項和其他設置 ...
  • 概述 當方法返回類型或屬性類型為集合時,有些開發者會千篇一律地使用IList集合。然而IList具有集合的所有操作,這意味著調用者不僅可以讀取集合信息,還能夠修改集合。業務需求本來只是為調用者提供一個可讀的集合,例如數據的查詢和展示,但當方法返回IList時,無疑隱式地開放了集合可寫的許可權。此時,我... ...
  • 之前由於剛入行不久,對數據持久化不是很瞭解,尤其是用資料庫存儲大量數據的操作。經過摸索就在此總結一下,方便以後查閱 下麵就簡單介紹一下: 1.NSUserDefaults 感覺最常用的小量數據,屬性,例如,賬號,密碼之類的;適合存儲輕量級的本地數據 (個人認為這種比較簡單) NSUserDefaul ...
  • 前面學起來還是很順的,畢竟很多都接觸過。 後面學起來只能用“磨”來形容,以至於八章用了2個月。(當然也有相當一些原因是這兩個月中發生了一些個人生活上的問題) 總的來說收穫超大,這種感覺就像大一的時候學習老譚的C語言一樣,醍醐灌頂。 如果是靠.NET吃飯的人,不讀這本書真的是太可惜了。 不過這中間也出 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...