// 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 將鎖物件封裝為私有靜態欄位,外部無法存取,保證鎖語意純粹。
CRITICAL_SECTION g_cs;
InitializeCriticalSection(&g_cs);
EnterCriticalSection(&g_cs); // 檢查 OwningThread,忙則等待
// 臨界區程式碼
LeaveCriticalSection(&g_cs);
DeleteCriticalSection(&g_cs);
CRITICAL_SECTION 核心欄位:LockCount、RecursionCount、OwningThread、LockSemaphore、SpinCount。
try { Monitor.Enter(obj); ... } finally { Monitor.Exit(obj); }
Monitor.Enter/Exit 標記 [MethodImpl(MethodImplOptions.InternalCall)],對應 Native JIT_MonEnter/JIT_MonExit。
JIT_MonEnterWorker_Portable → OBJECTREF::EnterObjMonitor()ObjHeader::EnterObjMonitor() → GetSyncBlock()->EnterMonitor()SyncBlock::EnterMonitor() → m_Monitor.Enter() (m_Monitor 為 AwareLock)
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。

SyncBlockIndex 初始為負數(無關聯)。Monitor.Enter 從全域 SyncBlock[] 取得空閒項,索引寫入物件頭。SyncBlock 內含 AwareLock 實現互斥與遞歸。下兩篇將揭示:
GetHashCode() 如何複用 SyncBlockIndex 儲存雜湊值。