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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.Net线程同步技术解读

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

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


什么是線程安全

教條式理解

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

結(jié)合場景理解

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

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

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

  • 增大 Size 的值。

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

    • 如果是在多線程場景下,有兩個線程,線程A先將元素存放在位置0,但是此時CPU調(diào)度線程A暫停,線程B得到運(yùn)行機(jī)會;線程B也向此ArrayList添加元素,因為此時Size仍然等于0 (注意哦,我們假設(shè)添加元素是經(jīng)過兩個步驟,而線程A僅僅完成了步驟1),所以線程B也將元素存放在位置0。然后線程A和線程B都繼續(xù)運(yùn)行,都增加 Size 的值。那好,我們來看看ArrayList的情況,元素實際上只有一個,存放在位置 0,而Size卻等于2,形成了臟數(shù)據(jù),這種就定義為對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 靜態(tài)屬性的操作是線程安全的:Any public static members of this type (HttpContext) are thread safe, any instance members are not guaranteed to be thread safe.

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

    線程同步技術(shù)

    話不多說,給出大圖:

    四象限對象的區(qū)別:

    • 支持線程進(jìn)入的個數(shù)

    • 是否跨進(jìn)程支持?

    上半?yún)^(qū) lock(Monitor), Mutex(中文稱為互斥鎖)都只支持單線程進(jìn)入被保護(hù)代碼,其他線程則必須等待進(jìn)入的線程完成 {Critical Section}

    下半?yún)^(qū)SemaphoreSlim、Semaphore(中文稱為信號量)支持并發(fā)多線程進(jìn)入被保護(hù)代碼,對象在初始化時會指定 最大信號燈數(shù)量,當(dāng)線程請求訪問資源,信號量遞減,而當(dāng)他們釋放時,信號量計數(shù)又遞增。

    左半?yún)^(qū)lock (Monitor)、SemaphoreSlim 是CRL對象,?進(jìn)程內(nèi)線程同步;?右半?yún)^(qū)Mutex,Semaphore都繼承自WaitHandle對象,支持命名,是內(nèi)核對象,在系統(tǒng)級別能支持進(jìn)程間線程同步。

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

    ?①?lock(Monitor)

    開發(fā)者最常用的lock關(guān)鍵字,使用方式相當(dāng)簡單,對于單進(jìn)程內(nèi)線程同步相當(dāng)有效,實際上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);
    }

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

    ? ?這里面有個SyncBlockIndex的概念,新建的托管堆在內(nèi)存表現(xiàn)如下:

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

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

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

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

    ② lock(Monitor)?vs SemaphoreSlim

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

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

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

    總結(jié)

    從宏觀上掌握Monitor,Mutex,SemaphoreSlim,Semaphore的區(qū)別有利于形成【線程同步知識體系】;文章著重記錄進(jìn)程內(nèi)線程同步技術(shù)。

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。