首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

同步區塊索引深度解析(上):從 lock 關鍵字到 AwareLock 實作原理

     編輯:關於.NET

四種 Lock 寫法優劣比較

// 1. 推薦:私有靜態唯讀物件
private static readonly object _lockHelper = new object();
lock (_lockHelper) { ... }

// 2. 錯誤:區域變數每次新建,無法互斥
object lockHelper = new object();
lock (lockHelper) { ... }

// 3. 危險:鎖定 Type 物件,跨元件易衝突
lock (typeof(Singleton)) { ... }

// 4. 危險:鎖定 this,外部可鎖定同一實例造成死結
lock (this) { ... }

結論: 唯有寫法 1 將鎖物件封裝為私有靜態欄位,外部無法存取,保證鎖語意純粹。

Win32 關鍵區域回顧

CRITICAL_SECTION g_cs;
InitializeCriticalSection(&g_cs);
EnterCriticalSection(&g_cs); // 檢查 OwningThread,忙則等待
// 臨界區程式碼
LeaveCriticalSection(&g_cs);
DeleteCriticalSection(&g_cs);

CRITICAL_SECTION 核心欄位:LockCount、RecursionCount、OwningThread、LockSemaphore、SpinCount。

CLR lock 對應 Monitor.Enter/Exit

try { Monitor.Enter(obj); ... } finally { Monitor.Exit(obj); }

Monitor.Enter/Exit 標記 [MethodImpl(MethodImplOptions.InternalCall)],對應 Native JIT_MonEnter/JIT_MonExit。

原始碼呼叫鏈追蹤 (Rotor)

  1. JIT_MonEnterWorker_Portable → OBJECTREF::EnterObjMonitor()
  2. ObjHeader::EnterObjMonitor() → GetSyncBlock()->EnterMonitor()
  3. SyncBlock::EnterMonitor() → m_Monitor.Enter() (m_Monitor 為 AwareLock)

AwareLock::Enter() 核心邏輯


void AwareLock::Enter()
{
    Thread* pCurThread = GetThread();
    for (;;)
    {
        LONG state = m_MonitorHeld;
        if (state == 0)
        {
            // 嘗試無競爭取得
            if (FastInterlockCompareExchange(&m_MonitorHeld, 1, 0) == 0) break;
        }
        else
        {
            // 遞歸檢查
            if (m_HoldingThread == pCurThread) { m_Recursion++; return; }
            // 計數等待者並進入等待
            if (FastInterlockCompareExchange(&m_MonitorHeld, state+2, state) == state)
                EnterEpilog(pCurThread); // 進入等待佇列
        }
    }
    m_HoldingThread = pCurThread;
    m_Recursion = 1;
    pCurThread->IncLockCount();
}

與 Win32 CRITICAL_SECTION 高度相似:m_MonitorHeld 對應 LockCount,m_HoldingThread 對應 OwningThread,m_Recursion 對應 RecursionCount。

物件與 SyncBlock 關係圖

Object -> SyncBlockIndex -> SyncBlock -> AwareLock

  • 物件標頭 SyncBlockIndex 初始為負數(無關聯)。
  • 首次 Monitor.Enter 從全域 SyncBlock[] 取得空閒項,索引寫入物件頭。
  • SyncBlock 內含 AwareLock 實現互斥與遞歸。

系列預告

下兩篇將揭示:

  • (中) GetHashCode() 如何複用 SyncBlockIndex 儲存雜湊值。
  • (下) 當物件同時作為 Lock 與需 HashCode 時,索引位元如何切換與資料遷移。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved