临界区的内部结构与实现

本文详细解析了Windows系统中临界区(_RTL_CRITICAL_SECTION)的内部结构和相关API的实现,包括LockCount、RecursionCount、OwningThread、SpinCount等字段的作用,以及RtlInitializeCriticalSectionAndSpinCount、RtlEnterCriticalSection和RtlLeaveCriticalSection的代码分析,揭示了临界区在多处理器系统中的优化策略和线程同步机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        做windows开发的人都知道临界区是应用层同步对象,相对于其它内核同步对象来说,等待临界区的开销比较小,其原因在于临界区采用忙等(自旋)的方式来避免线程切换。这些原理性知识大家都比较清楚,但对于它的实现细节就不是每个人都了解了。我在这方面也曾经存在困惑,后来通过分析它的结构以及相关几个API的实现,总算有了比较清楚的认识。

       在windows系统内部, 临界区的结构体叫做_RTL_CRITICAL_SECTION,在windbg中可以用dt命令打印出它的结构:

:006> dt_RTL_CRITICAL_SECTION

ntdll!_RTL_CRITICAL_SECTION

   +0x000 DebugInfo        : Ptr32 _RTL_CRITICAL_SECTION_DEBUG

   +0x004 LockCount        : Int4B

   +0x008 RecursionCount    :Int4B

   +0x00cOwningThread     : Ptr32 Void

   +0x010 LockSemaphore    : Ptr32 Void

   +0x014 SpinCount         :Uint4B

        DebugInfo,此字段包含一个指针,指向系统分配的伴随结构,该结构的类型为RTL_CRITICAL_SECTION_DEBUG。这一结构中包含更多极有价值的信息,也定义于 WINNT.H 中。

        LockCount,这是临界区中最重要的一个字段。它被初始化为数值 -1;此数值等于或大于 0 时,表示此临界区被占用。当其不等于 -1 时,OwningThread 字段(此字段被错误地定义于 WINNT.H 中 — 应当是 DWORD 而不是 HANDLE)包含了拥有此临界区的线程 ID。此字段与 (RecursionCount -1) 数值之间的差值表示有多少个其他线程在等待获得该临界区。

        RecursionCount,此字段包含所有者线程已经获得该临界区的次数。如果该数值为零,下一个尝试获取该临界区的线程将会成功。

        OwningThread,此字段包含当前占用此临界区的线程的线程标识符。此线程 ID 与 GetCurrentThreadId 之类的 API 所返回的 ID 相同。

        LockSemaphore,此字段的命名不恰当,它实际上是一个自复位事件,而不是一个信号。它是一个内核对象句柄,用于通知操作系统:该临界区现在空闲。操作系统在一个线程第一次尝试获得该临界区,但被另一个已经拥有该临界区的线程所阻止时,自动创建这样一个句柄。应当调用 DeleteCriticalSection(它将发出一个调用该事件的 CloseHandle 调用,并在必要时释放该调试结构),否则将会发生资源泄漏。

        SpinCount,仅用于多处理器系统。MSDN® 文档对此字段进行如下说明:“在多处理器系统中,如果该临界区不可用,调用线程将在对与该临界区相关的信号执行等待操作之前,旋转 dwSpinCount 次。如果该临界区在旋转操作期间变为可用,该调用线程就避免了等待操作。”旋转计数可以在多处理器计算机上提供更佳性能,其原因在于在一个循环中旋转通常要快于进入内核模式等待状态。此字段默认值为零,但可以用 InitializeCriticalSectionAndSpinCount API 将其设置为一个不同值。

        结合临界区的结构,再看看相关的几个API的具体实现,临界区对象就算是了解清楚了,下面是几个API的代码分析(代码有省略):

ntdll!RtlInitializeCriticalSectionAndSpinCount:

7c93151a     mov    edi,edi

7c93151c     push    ebp

7c93151d     mov     ebp,esp

7c93151f     sub     esp,20h

7c931522     push    ebx

7c931523     xor     ebx,ebx

7c931525     push    edi

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值