自旋锁和互斥锁实例_C#多线程编程中的锁系统(四):自旋锁

博客展示了自旋锁Enter方法的代码实现,包含快速获取锁和慢速获取锁的逻辑。快速路径失败后会进入慢速路径,慢速路径又分为更新等待者、自旋和让步三个步骤,还包含超时检查和减少等待者数量等操作。

public void Enter(ref bool lockTaken)

{

if (lockTaken)

{

lockTaken = false;

throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));

}

// Fast path to acquire the lock if the lock is released

// If the thread tracking enabled set the new owner to the current thread id

// Id not, set the anonymous bit lock

int observedOwner = m_owner;

int newOwner = 0;

bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;

if (threadTrackingEnabled)

{

if (observedOwner == LOCK_UNOWNED)

newOwner = Thread.CurrentThread.ManagedThreadId;

}

else if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)

{

newOwner = observedOwner | LOCK_ANONYMOUS_OWNED; // set the lock bit

}

if (newOwner != 0)

{

#if !FEATURE_CORECLR

Thread.BeginCriticalRegion();

#endif

#if PFX_LEGACY_3_5

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)

{

lockTaken = true;

return;

}

#else

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)

{

// Fast path succeeded

return;

}

#endif

#if !FEATURE_CORECLR

Thread.EndCriticalRegion();

#endif

}

//Fast path failed, try slow path

ContinueTryEnter(Timeout.Infinite, ref lockTaken);

}

private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)

{

long startTicks = 0;

if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)

{

startTicks = DateTime.UtcNow.Ticks;

}

#if !FEATURE_PAL && !FEATURE_CORECLR   // PAL doesn't support  eventing, and we don't compile CDS providers for Coreclr

if (CdsSyncEtwBCLProvider.Log.IsEnabled())

{

CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner);

}

#endif

if (IsThreadOwnerTrackingEnabled)

{

// Slow path for enabled thread tracking mode

ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken);

return;

}

// then thread tracking is disabled

// In this case there are three ways to acquire the lock

// 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2

// 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn

// the late the thread arrives the more it spins and less frequent it check the lock avilability

// Also the spins count is increaes each iteration

// If the spins iterations finished and failed to acquire the lock, go to step 3

// 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1)

// If the timeout is expired in after step 1, we need to decrement the waiters count before returning

int observedOwner;

//***Step 1, take the lock or update the waiters

// try to acquire the lock directly if possoble or update the waiters count

SpinWait spinner = new SpinWait();

while (true)

{

observedOwner = m_owner;

if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)

{

#if !FEATURE_CORECLR

Thread.BeginCriticalRegion();

#endif

#if PFX_LEGACY_3_5

if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner) == observedOwner)

{

lockTaken = true;

return;

}

#else

if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)

{

return;

}

#endif

#if !FEATURE_CORECLR

Thread.EndCriticalRegion();

#endif

}

else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow

if ((observedOwner & WAITERS_MASK) ==  MAXIMUM_WAITERS || Interlocked.CompareExchange(ref m_owner, observedOwner + 2, observedOwner) == observedOwner)

break;

spinner.SpinOnce();

}

// Check the timeout.

if (millisecondsTimeout == 0 ||

(millisecondsTimeout != Timeout.Infinite &&

TimeoutExpired(startTicks, millisecondsTimeout)))

{

DecrementWaiters();

return;

}

//***Step 2. Spinning

//lock acquired failed and waiters updated

int turn = ((observedOwner + 2) & WAITERS_MASK) / 2;

int processorCount = PlatformHelper.ProcessorCount;

if (turn < processorCount)

{

int processFactor = 1;

for (int i = 1; i <= turn * SPINNING_FACTOR; i++)

{

Thread.SpinWait((turn + i) * SPINNING_FACTOR * processFactor);

if (processFactor < processorCount)

processFactor++;

observedOwner = m_owner;

if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)

{

#if !FEATURE_CORECLR

Thread.BeginCriticalRegion();

#endif

int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero

observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters

: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit

Contract.Assert((newOwner & WAITERS_MASK) >= 0);

#if PFX_LEGACY_3_5

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)

{

lockTaken = true;

return;

}

#else

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)

{

return;

}

#endif

#if !FEATURE_CORECLR

Thread.EndCriticalRegion();

#endif

}

}

}

// Check the timeout.

if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout))

{

DecrementWaiters();

return;

}

//*** Step 3, Yielding

//Sleep(1) every 50 yields

int yieldsoFar = 0;

while (true)

{

observedOwner = m_owner;

if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)

{

#if !FEATURE_CORECLR

Thread.BeginCriticalRegion();

#endif

int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero

observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters

: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit

Contract.Assert((newOwner & WAITERS_MASK) >= 0);

#if PFX_LEGACY_3_5

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)

{

lockTaken = true;

return;

}

#else

if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)

{

return;

}

#endif

#if !FEATURE_CORECLR

Thread.EndCriticalRegion();

#endif

}

if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0)

{

Thread.Sleep(1);

}

else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0)

{

Thread.Sleep(0);

}

else

{

#if PFX_LEGACY_3_5

Platform.Yield();

#else

Thread.Yield();

#endif

}

if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0)

{

//Check the timeout.

if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout))

{

DecrementWaiters();

return;

}

}

yieldsoFar++;

}

}

///

/// decrements the waiters, in case of the timeout is expired

///

private void DecrementWaiters()

{

SpinWait spinner = new SpinWait();

while (true)

{

int observedOwner = m_owner;

if ((observedOwner & WAITERS_MASK) == 0) return; // don't decrement the waiters if it's corrupted by previous call of Exit(false)

if (Interlocked.CompareExchange(ref m_owner, observedOwner - 2, observedOwner) == observedOwner)

{

Contract.Assert(!IsThreadOwnerTrackingEnabled); // Make sure the waiters never be negative which will cause the thread tracking bit to be flipped

break;

}

spinner.SpinOnce();

}

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值