日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

.Net线程同步技术解读

發布時間:2023/12/4 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .Net线程同步技术解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C#開發者(面試者)都會遇到lock(Monitor),Mutex,Semaphore,SemaphoreSlim這四個與鎖相關的C#類型,本文期望以最簡潔明了的方式闡述四種對象的區別。


什么是線程安全

教條式理解

如果代碼在多線程環境中運行的結果與單線程運行結果一樣,其他變量值也和預期是一樣的,那么線程就是安全的;

結合場景理解

兩個線程都為集合增加元素,我們錯誤的理解即使是多線程也總有先后順序吧,集合的兩個位置先后塞進去就完了;實際上集合增加元素這個行為看起來簡單,實際并不一定是原子操作。

在添加一個元素的時候,它可能會有兩步來完成:

  • 在 Items[Size] 的位置存放此元素;

  • 增大 Size 的值。

    • 在單線程運行的情況下,如果 Size = 0,添加一個元素后,此元素在位置0,之后設置Size=1;

    • 如果是在多線程場景下,有兩個線程,線程A先將元素存放在位置0,但是此時CPU調度線程A暫停,線程B得到運行機會;線程B也向此ArrayList添加元素,因為此時Size仍然等于0 (注意哦,我們假設添加元素是經過兩個步驟,而線程A僅僅完成了步驟1),所以線程B也將元素存放在位置0。然后線程A和線程B都繼續運行,都增加 Size 的值。那好,我們來看看ArrayList的情況,元素實際上只有一個,存放在位置 0,而Size卻等于2,形成了臟數據,這種就定義為對ArrayList的新增元素操作是線程不安全的。

    線程安全這個問題不單單存在于集合類,我們始終要記得:
    Never ever modify a shared resource by multipie threads unless resource is thread-safe.

    我們對SqlServer,Mongodb,對HttpContext的訪問都會涉及thread-safe。

    - 利用C#?mongodb driver操作Mongo打包時常用操作是線程安全的,Only a few of the C# Driver classes are thread safe. Among them: MongoServer, MongoDatabase, MongoCollection and MongoGridFS.

    - 對于HttpContext 靜態屬性的操作是線程安全的:Any public static members of this type (HttpContext) are thread safe, any instance members are not guaranteed to be thread safe.

    各語言推出了適用于不同范圍的線程同步技術來預防以上臟數據(實現線程安全)

    線程同步技術

    話不多說,給出大圖:

    四象限對象的區別:

    • 支持線程進入的個數

    • 是否跨進程支持?

    上半區 lock(Monitor), Mutex(中文稱為互斥鎖)都只支持單線程進入被保護代碼,其他線程則必須等待進入的線程完成 {Critical Section}

    下半區SemaphoreSlim、Semaphore(中文稱為信號量)支持并發多線程進入被保護代碼,對象在初始化時會指定 最大信號燈數量,當線程請求訪問資源,信號量遞減,而當他們釋放時,信號量計數又遞增。

    左半區lock (Monitor)、SemaphoreSlim 是CRL對象,?進程內線程同步;?右半區Mutex,Semaphore都繼承自WaitHandle對象,支持命名,是內核對象,在系統級別能支持進程間線程同步。

    進程間線程同步不多見(分布式鎖的場景越來越多,這里按下不表),啰嗦一下常見的進程內線程同步技術:

    ?①?lock(Monitor)

    開發者最常用的lock關鍵字,使用方式相當簡單,對于單進程內線程同步相當有效,實際上lock是Monitor的語法糖,實際的編譯代碼如下:

    object?__lockObj?=?x;
    bool?__lockWasTaken?=?false;
    try
    {
    ?????System.Threading.Monitor.Enter(__lockObj,?ref?__lockWasTaken);
    ?????//?Your?code...
    }
    finally
    {
    ????if?(__lockWasTaken)?System.Threading.Monitor.Exit(__lockObj);
    }

    一般使用私有靜態對象作為lock(Monitor)線程同步的同步對象,那配合lock完成代碼鎖定的那個對象到底起什么作用呢?

    ? ?這里面有個SyncBlockIndex的概念,新建的托管堆在內存表現如下:

    ? 每個堆對象:函數表指針(這也是一個重要知識點,用于在多態中判斷對象到底是哪個類型)、同步塊索引、對象字段;其中同步塊索引是lock解決線程同步的關鍵,SyncBlockIndex是一個地址指針(傳送門);

    新創建的對象objLock,其SyncBlockindex =-1,不指向任何有效同步塊;

    調用靜態類Monitor.Enter(objLock), CRL會尋找一個空閑SyncBlock并將objLock對象的SyncBlockIndex指向該塊, 例如上圖中ObjectA,ObjectC的SyncBlockIndex指向了2個SyncBlock;

    Exit(objLock)會將objLock對象的SyncBlockIndex重新賦為 -1, 釋放出來的SyncBlock可以在將來被其他對象SyncBlockIndex引用。

    ② lock(Monitor)?vs SemaphoreSlim

    ????兩者都是進程內線程同步技術,SemaphoreSlim信號量支持多線程進入;另外SemaphoreSlim 有異步等待方法,支持在異步代碼中線程同步,解決在async code中無法使用lock語法糖的問題

    //?實例化單信號量
    static?SemaphoreSlim?semaphoreSlim?=?new?SemaphoreSlim(1,1);

    //?異步等待進入信號量,如果沒有線程被授予對信號量的訪問權限,則進入執行保護代碼;否則此線程將在此處等待,直到信號量被釋放為止
    await?semaphoreSlim.WaitAsync();
    try
    {
    ????await?Task.Delay(1000);
    }
    finally
    {
    ????//?任務準備就緒后,釋放信號燈。【準備就緒時始終釋放信號量】至關重要,否則我們將獲得永遠被鎖定的信號量
    ????semaphoreSlim.Release();
    }

    總結

    從宏觀上掌握Monitor,Mutex,SemaphoreSlim,Semaphore的區別有利于形成【線程同步知識體系】;文章著重記錄進程內線程同步技術。

    總結

    以上是生活随笔為你收集整理的.Net线程同步技术解读的全部內容,希望文章能夠幫你解決所遇到的問題。

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