.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ì)使用它的最大性能來(lái)不斷的進(jìn)行賦值和比較指令,會(huì)浪費(fèi)很大的性能,Thread.SpinWait提示CPU當(dāng)前正在自旋鎖的循環(huán)中,可以休息若干個(gè)時(shí)間周期
- 使用自旋鎖需要注意的問(wèn)題,自旋鎖保護(hù)的代碼應(yīng)該在非常短的時(shí)間內(nèi)執(zhí)行完成,如果時(shí)間過(guò)長(zhǎng),其他線程不斷重試導(dǎo)致影響其他線程進(jìn)行
缺點(diǎn):
當(dāng)前實(shí)現(xiàn)沒(méi)有考慮到公平性,如果多個(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ù);如果超過(guò)一定次數(shù)或者當(dāng)前環(huán)境邏輯核心數(shù)等于1,則交替使用
Thread.Sleep(0)和Thread.Yield函數(shù),表示切換到其他線程,如果再超過(guò)一定次數(shù),則讓當(dāng)前線程休眠
SpinWaite解決Thread.SpinWait中的兩個(gè)問(wèn)題
- 如果自旋鎖運(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)無(wú)法重新進(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)中沒(méi)有區(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)文章
ASP.NET中DropDownList和ListBox實(shí)現(xiàn)兩級(jí)聯(lián)動(dòng)功能
這篇文章主要介紹了ASP.NET中DropDownList和ListBox實(shí)現(xiàn)兩級(jí)聯(lián)動(dòng)功能的相關(guān)資料,需要的朋友可以參考下2016-01-01
asp.net無(wú)法獲取iis目錄的問(wèn)題解決方法
本文介紹了Asp.Net無(wú)法獲取IIS拾取目錄的解決辦法,需要的朋友可以參考下2014-02-02
詳解使用DotNet CLI創(chuàng)建自定義的WPF項(xiàng)目模板
這篇文章主要介紹了詳解使用DotNet CLI創(chuàng)建自定義的WPF項(xiàng)目模板,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
MVC使用T4模板生成其他類的具體實(shí)現(xiàn)學(xué)習(xí)筆記2
這篇文章主要為大家詳細(xì)介紹了MVC使用T4模板生成其他類的具體實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
log4net教程日志分類和自動(dòng)維護(hù)示例
log4net能不能按照功能分類呢?如果通過(guò)配置不同的logger,然后功能根據(jù)不同的LoggerName加載Ilog實(shí)例,是可以做到。但由于這些功能的log配置差異性極小,也許僅僅就是文件名不同。于是想通過(guò)代碼進(jìn)行配置,下面把方法分享如下2014-01-01
擴(kuò)展 Entity Framework支持復(fù)雜的過(guò)濾條件(多個(gè)關(guān)鍵字模糊匹配)
之前遇到一個(gè)棘手的Linq to EF查詢的技術(shù)問(wèn)題,現(xiàn)有產(chǎn)品表Product,需要根據(jù)多個(gè)關(guān)鍵字模糊匹配產(chǎn)品名稱, 現(xiàn)將解決方案分享出來(lái),按興趣的朋友可以參考下2012-12-12
詳解在Windows下如何使用AspNetCore Api 和consul
這篇文章主要介紹了詳解在Windows下如何使用AspNetCore Api 和consul,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

