1. 程式人生 > >30.2 自旋、執行緒所有權和遞迴

30.2 自旋、執行緒所有權和遞迴

 

    /// <summary>
    /// 其他混合鎖
    /// </summary>
    internal sealed class AnotherHybridLock : IDisposable
    {
        //由基元使用者模式構造(Interlocked的方法)使用
        private int _waiters = 0;

        //AutoResetEvent 是基元核心模式構造
        private AutoResetEvent _waiterLock = new AutoResetEvent(false
); //這個欄位控制自旋,希望提升效能 private int _spinCount = 4000; //隨便選擇的一個計數 //這些欄位指出哪個執行緒擁有鎖,以及擁有了它多少次 private int _owingThreadId = 0, _recursion = 0; public void Enter() { //如果呼叫執行緒已經擁有鎖,遞增遞迴計數並返回 int threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId == _owingThreadId) { _recursion++; return; } //呼叫的執行緒不再擁有鎖,嘗試獲取它 SpinWait spinwait = new SpinWait(); for (int i = 0; i < _spinCount; i++) { //如果鎖可以自由使用了,這個執行緒就獲得它:設定一些狀態並返回
if (Interlocked.CompareExchange(ref _waiters, 1, 0) == 0) goto GotLock; //黑科技:給其他執行緒執行的機會,希望鎖會被釋放 spinwait.SpinOnce(); } //自旋結束,鎖仍未獲得,再試一次 if (Interlocked.Increment(ref _waiters) > 1) { //仍然是競態條件,這個執行緒必須阻塞 _waiterLock.WaitOne(); //等待鎖:效能有損失 //等待這個執行緒醒來時,它擁有鎖:設定一些狀態並返回 } GotLock: //一個執行緒獲得鎖時,我們記錄它的ID,並指出執行緒擁有鎖一次 _owingThreadId = threadId; _recursion = 1; } public void Leave() { //如果呼叫執行緒不再擁有鎖,表明存在bug int threadId = Thread.CurrentThread.ManagedThreadId; if (threadId != _owingThreadId) throw new SynchronizationLockException("Lock not owned by calling thread"); //遞減遞迴計數。如果這個執行緒仍然擁有鎖,那麼直接返回 if (--_recursion > 0) return; _owingThreadId = 0; //現在沒有執行緒擁有鎖 //如果沒有其他執行緒在等待,直接返回 if (Interlocked.Decrement(ref _waiters) == 0) return; //有其他執行緒正在阻塞,喚醒其中一個 _waiterLock.Set(); //這裡產生較大的效能影響 } public void Dispose() { _waiterLock.Dispose(); } }