计算机科学

首页 > 计算机科学

临界区块

2018-08-31 09:32:06     所属分类:程序架构

在同步的程序设计中,临界区块Critical section)指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源有无法同时被多个线程访问的特性。

当有线程进入临界区块时,其他线程或是进程必须等待(例如:bounded waiting 等待法),有一些同步的机制必须在临界区块的进入点与离开点实现,以确保这些共用资源是被互斥或的使用,例如:semaphore。

只能被单一线程访问的设备,例如:打印机。

一个最简单的实现方法就是当线程(Thread)进入临界区块时,禁止改变处理器;在uni-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 此字段仅用于诊断情形中。在注册表项 HKLMSoftwareMicrosoftWindows NTCurrentVersionImage File Execution OptionsYourProgram 之下是 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 这两个字段未使用,甚至未被初始化。

外部链接

MSDN Library -- Critical section



猜你喜欢

相关推荐