【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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...