臨界區段

在同步的程式設計中，臨界區段（）或稱為关键区段 ，指的是一個存取共用資源（例如：共用裝置或是共用記憶體）的程式片段，而這些共用資源又無法同時被多個執行緒存取的特性。

當有執行緒進入臨界區段時，其他執行緒或是行程必須等待（例如：bounded waiting 等待法），有一些同步的機制必須在臨界區段的進入點與離開點實現，以確保這些共用資源是被互斥或的使用，例如：semaphore。

只能被單一執行緒存取的裝置，例如：印表機。

一個最簡單的實現方法就是當執行緒（Thread）進入臨界區段時，禁止改變處理器；在Single-Processor系統上，可以用「禁止中斷（CLI）」來完成，避免发生系统调用（System Call）导致的上下文交換（Context switching）；當離開臨界區段時，處理器回復原先的狀態。

 Windows操作系统的临界区
在Windows操作系统，CRITICAL_SECTION是一种同步对象类型，用于同一个进程内的多线程同步访问资源。如果是跨进程同步，需要使用互斥锁（mutex）。 

临界区对象首先需要初始化，通过调用操作系统API函数InitializeCriticalSection。各个线程调用函数 EnterCriticalSection, TryEnterCriticalSection, 或LeaveCriticalSection来使用临界区。使用结束后或者重初始化临界区之前，需要调用 DeleteCriticalSection 。

WINNT.H中定义的临界区数据结构如下：
struct RTL_CRITICAL_SECTION
{
   PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
   LONG LockCount;
   LONG RecursionCount;
   HANDLE OwningThread;
   HANDLE LockSemaphore;
   ULONG_PTR SpinCount;
};
结构的各域的解释：
 DebugInfo 此字段为一个指针，指向系统分配的结构RTL_CRITICAL_SECTION_DEBUG。这一结构中包含更多极有价值的信息，也定义于 WINNT.H 中。
 LockCount 被初始化为数值 -1；此数值等于或大于 0 时，表示此临界区被占用。当其不等于 -1 时，OwningThread 字段包含了拥有此临界区的线程 ID。此字段与 (RecursionCount-1) 数值之间的差值表示有多少个其他线程在等待获得该临界区。
 RecursionCount 初始值为0. 此字段包含所有者线程已经获得该临界区的次数。如果该数值为零，下一个尝试获取该临界区的线程将会成功。
 OwningThread 此字段包含当前占用此临界区的线程的线程标识符（应为DWORD而不是HANDLE）。此线程 ID 与 GetCurrentThreadId 之类的 API 所返回的 ID 相同。
 LockSemaphore 是一个自复位的Event内核对象句柄。首次发生线程申请该临界区被阻止时，操作系统自动创建该句柄。应当调用 DeleteCriticalSection（它将发出一个调用该事件的 CloseHandle 调用，并在必要时释放该调试结构），否则将会发生资源泄漏。
 SpinCount 仅用于多处理器系统。MSDN文档：“在多处理器系统中，如果该临界区不可用，调用线程将在对与该临界区相关的信号执行等待操作之前，旋转 dwSpinCount 次。如果该临界区在旋转操作期间变为可用，该调用线程就避免了等待操作。”自旋计数可以在多处理器计算机上提供更佳性能，其原因在于在一个循环中自旋通常要快于进入内核模式等待状态。此字段默认值为零，但可以用InitializeCriticalSectionAndSpinCount API 将其设置为一个不同值。

RTL_CRITICAL_SECTION_DEBUG结构如下：
struct _RTL_CRITICAL_SECTION_DEBUG
{
    WORD   Type;
    WORD   CreatorBackTraceIndex;
    RTL_CRITICAL_SECTION *CriticalSection;
    LIST_ENTRY ProcessLocksList;
    DWORD EntryCount;
    DWORD ContentionCount;
    DWORD Spare[ 2 ];
}
结构的各域的解释：
 Type 此字段未使用，被初始化为数值 0。
 CreatorBackTraceIndex 此字段仅用于诊断情形中。在注册表项 HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\YourProgram 之下是 keyfield、GlobalFlag 和 StackTraceDatabaseSizeInMb 值。注意，只有在运行稍后说明的 Gflags 命令时才会显示这些值。这些注册表值的设置正确时，CreatorBackTraceIndex 字段将由堆栈跟踪中所用的一个索引值填充。在 MSDN 中搜索 GFlags 文档中的短语“create user mode stack trace database”和“enlarging the user-mode stack trace database”。
 CriticalSection 指向与此结构相关的 RTL_CRITICAL_SECTION 
 ProcessLocksList： LIST_ENTRY 是用于表示双向链表中节点的标准 Windows 数据结构。RTL_CRITICAL_SECTION_DEBUG 包含了链表的一部分，允许向前和向后遍历该临界区。Flink=NULL为表头，Blink=NULL为表尾 
 EntryCount/ContentionCount 这些字段在相同的时间、出于相同的原因被递增。这是不能获得临界区而进入等待状态的线程的数目。与 LockCount 和 RecursionCount 字段不同，这些字段永远都不会递减。
 Spares 这两个字段未使用，甚至未被初始化。

 參考資料 

 參見 
 資料庫交易
 Lamport麵包店算法
 鎖 (電腦科學)
 互斥鎖
 Peterson算法
 Szymanski算法

 外部連結 
MSDN Library -- Critical section 

Category:并发控制
Category:程序架構