.Net基于Thread實(shí)現(xiàn)自旋鎖的三種方式
基于Thread.SpinWait實(shí)現(xiàn)自旋鎖
實(shí)現(xiàn)原理:基于Test--And--Set原子操作實(shí)現(xiàn)
使用一個(gè)數(shù)據(jù)表示當(dāng)前鎖是否已經(jīng)被獲取 0表示未被索取,1表示已經(jīng)獲取 獲取鎖時(shí)會(huì)將_lock的值設(shè)置為1 然后檢查修改前的值是否等于0,
優(yōu)點(diǎn):
- 不使用Thread.SpinWait方法,重試的方法體會(huì)為空,CPU會(huì)使用它的最大性能來不斷的進(jìn)行賦值和比較指令,會(huì)浪費(fèi)很大的性能,Thread.SpinWait提示CPU當(dāng)前正在自旋鎖的循環(huán)中,可以休息若干個(gè)時(shí)間周期
- 使用自旋鎖需要注意的問題,自旋鎖保護(hù)的代碼應(yīng)該在非常短的時(shí)間內(nèi)執(zhí)行完成,如果時(shí)間過長(zhǎng),其他線程不斷重試導(dǎo)致影響其他線程進(jìn)行
缺點(diǎn):
當(dāng)前實(shí)現(xiàn)沒有考慮到公平性,如果多個(gè)線程同時(shí)獲取鎖失敗,按時(shí)間順序第一個(gè)獲取鎖的線程不一定會(huì)在釋放鎖后第一個(gè)獲取成功,
代碼實(shí)現(xiàn):
public static class ThreadSpinWaitDemo { private static int _lock = 0; private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { while (Interlocked.Exchange(ref _lock, 1) != 0) { Thread.SpinWait(1); } ++_counterA; ++_counterB; Interlocked.Exchange(ref _lock, 0); } public static void GetCounters(out int counterA, out int counterB) { while (Interlocked.Exchange(ref _lock, 1) != 0) { Thread.SpinWait(1); } counterA = _counterA; counterB = _counterB; Interlocked.Exchange(ref _lock, 0); } }
基于SpinWaite實(shí)現(xiàn)自旋鎖
特性是SpinOnce方法的次數(shù),如果在一定次數(shù)以內(nèi)并且當(dāng)前邏輯核心所大于1,則調(diào)用Thread.SpinWait函數(shù);如果超過一定次數(shù)或者當(dāng)前環(huán)境邏輯核心數(shù)等于1,則交替使用
Thread.Sleep(0)和Thread.Yield函數(shù),表示切換到其他線程,如果再超過一定次數(shù),則讓當(dāng)前線程休眠
SpinWaite解決Thread.SpinWait中的兩個(gè)問題
- 如果自旋鎖運(yùn)行時(shí)間超長(zhǎng),SpinWaite可以提示操作系統(tǒng)切換到其他線程或者讓當(dāng)前線程進(jìn)入休眠狀態(tài),
- 如果當(dāng)前環(huán)境只有一個(gè)核心邏輯,SpinWaite不會(huì)執(zhí)行Thread.SpinWait函數(shù),而是直接提示操作系統(tǒng)切換到其他線程,
public static class ThreadSpinOnceDemo { private static int _lock = 0; private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { var spinWait = new SpinWait(); while (Interlocked.Exchange(ref _lock, 1) != 0) { spinWait.SpinOnce(); } ++_counterA; ++_counterB; Interlocked.Exchange(ref _lock, 0); } public static void GetCounters(out int counterA, out int counterB) { var spinWait = new SpinWait(); while (Interlocked.Exchange(ref _lock, 1) != 0) { spinWait.SpinOnce(); } counterA = _counterA; counterB = _counterB; Interlocked.Exchange(ref _lock, 0); } }
基于SpinLock實(shí)現(xiàn)自旋鎖
封裝了SpinWaite的邏輯
SpinLock代碼實(shí)現(xiàn)
public class ThreadSpinLockDemo { private static SpinLock _spinLock = new SpinLock(); private static int _counterA = 0; private static int _counterB = 0; public static void IncrementCounters() { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); ++_counterA; ++_counterB; } finally { if (lockTaken) { _spinLock.Exit(); } } } public static void GetCounters(out int counterA, out int counterB) { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); counterA = _counterA; counterB = _counterB; } finally { if (lockTaken) { _spinLock.Exit(); } } } }
簡(jiǎn)述 Thread.Sleep(0)和Thread.Yield的區(qū)別
- 在Windows系統(tǒng)中 Thread.Sleep調(diào)用系統(tǒng)提供的SleepEx函數(shù),Thread.Yield函數(shù)調(diào)用的是系統(tǒng)提供的SwitchToThread方法,
- 區(qū)別在于SwitchToThread函數(shù)只會(huì)切換到當(dāng)前核心邏輯關(guān)聯(lián)的待運(yùn)行隊(duì)列的線程,不會(huì)切換到其他核心邏輯關(guān)聯(lián)的線程上,而SleepEx函數(shù)會(huì)切換到任意邏輯核心關(guān)聯(lián)的待運(yùn)行隊(duì)列中的線程,并且讓當(dāng)前線程在指定時(shí)間內(nèi)無法重新進(jìn)入待運(yùn)行隊(duì)列(如果線程為0 那么線程可以立刻重新進(jìn)入待運(yùn)行隊(duì)列)
- 在Linux和OSX中 Thread.Sleep函數(shù)在休眠時(shí)間不為0時(shí)會(huì)調(diào)用pthread類庫(kù)提供的pthread_cond_timedWait函數(shù),在休眠時(shí)間為0時(shí)會(huì)調(diào)用sched_yield函數(shù),Thread.Yield同樣會(huì)調(diào)用sched_yield函數(shù) sched_yield在windows和osx系統(tǒng)中沒有區(qū)別,都只會(huì)切換到當(dāng)前和邏輯核心關(guān)心的待運(yùn)行隊(duì)列中的線程,不會(huì)切換到其他核心邏輯關(guān)聯(lián)的線程上。在unix系統(tǒng)上調(diào)用系統(tǒng)提供的sleep函數(shù)并傳入0 會(huì)直接忽略返回
以上就是.Net基于Thread實(shí)現(xiàn)自旋鎖的三種方式的詳細(xì)內(nèi)容,更多關(guān)于.Net自旋鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
TreeNodeCheckChanged事件觸發(fā)方法代碼實(shí)例
這篇文章主要介紹了TreeNodeCheckChanged事件觸發(fā)方法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12WPF實(shí)現(xiàn)定時(shí)刷新UI界面功能
這篇文章主要為大家詳細(xì)介紹了WPF實(shí)現(xiàn)定時(shí)刷新UI界面功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07asp.net實(shí)現(xiàn)XML文件讀取數(shù)據(jù)綁定到DropDownList的方法
這篇文章主要介紹了asp.net實(shí)現(xiàn)XML文件讀取數(shù)據(jù)綁定到DropDownList的方法,結(jié)合實(shí)例形式分析了asp.net針對(duì)xml文件操作及DropDownList控件的使用技巧,需要的朋友可以參考下2017-02-02.net讓線程支持超時(shí)的方法實(shí)例和線程在執(zhí)行結(jié)束后銷毀的方法
兩個(gè)問題:.net如何讓線程支持超時(shí)?.net如何讓線程在執(zhí)行結(jié)束后銷毀?本文就解決這二個(gè)問題2013-11-11ASP.NET MVC5網(wǎng)站開發(fā)概述(一)
這篇文章主要內(nèi)容是ASP.NET MVC5網(wǎng)站開發(fā)實(shí)踐的整體概述,分析了開發(fā)環(huán)境、使用的技術(shù)以及項(xiàng)目的整體結(jié)構(gòu),感興趣的小伙伴們可以參考一下2015-09-09linq to sql 中,如何解決多條件查詢問題,答案,用表達(dá)式樹! (下)
在上一篇中,我們做了基于linq to sql 的多條件組合查詢,但通過監(jiān)視數(shù)據(jù)庫(kù)發(fā)現(xiàn),這樣做的成本比較高,每次都要取出全部的數(shù)據(jù)到內(nèi)存進(jìn)行篩選.2011-08-08注冊(cè)表中存儲(chǔ)數(shù)據(jù)庫(kù)鏈接字符串的方法
2008-01-01