关键部分概述:
用于多线程互斥访问。 如果多个线程尝试同时访问关键节,则在一个线程进入关键节后,其他线程将挂起,直到进入关键节的线程离开。 临界区域释放后,其他线程可以继续抢占,实现对临界区域的独占访问。 (在临界区域一般是短代码段。)
在WINDOWS上,关键节是APP应用层的同步对象,而不是内核对象。 然后临界区域优先被旋转方式切断
关键部分API :
初始化和删除关键节:
初始化安全性()
DeleteCriticalSection () )
临界区的两个操作原语:
企业安全(
LeaveCriticalSection (
关键数据结构:
typedef struct _ RTL _ critical _ section {
prtl _ critical _ section _ debug debug info;
//
//thefollowingthreefieldscontrolenteringandexitingthecritical
//section for the resource
//
长锁定计数;
长记录计数;
HANDLE OwningThread; //from the thread ' s clientid-unique thread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; //forcesizeon 64-bitsystemswhenpacked
} RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION;
_RTL_CRITICAL_SECTION_DEBUG数据结构
typedef struct _ RTL _ critical _ section _ debug {
WORD Type;
WORD CreatorBackTraceIndex;
sru CT _ RTL _ critical _ section * critical section;
LIST_ENTRY ProcessLocksList;
DWORD EntryCount;
DWORD ContentionCount;
DWORD Flags;
WORD CreatorBackTraceIndexHigh;
WORD SpareWORD;
} RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*prtl_resource
_RTL_CRITICAL_SECTION中每个字段的说明:
DebugInfo:是指RTL_CRITICAL_SECTION_DEBUG类型的调试数据
LockCount:初始值-1,如果结果大于或等于0,则表示临界区域被线程占用。
OwningThread:当前有一个关键节线程
RecursionCount:所有者线程连续进入关键节的次数
LockSemaphore:内核对象句柄用于通知操作系统当前处于空闲状态,并用于在等待关键节时启动挂起的线程
SpinCount:MSDN对该字段的描述如下:
' On multiprocessor systems,ifthecriticalsectionisunavailable,the calling thread will spin
wspincounttimesbeforeperformingawaitoperationonasemaphoreassociatedwiththecritical
section.ifthecriticalsectionbecomesfreeduringthespinoperation,the calling thread
avoids the wait operation.'
在多处理器系统中,当临界区域已经被占用时,线程不是通过块待机方式获取临界区域,而是通过SpinCount次旋转获取临界区域。 自旋过程中如果有临界区域的空间,可以直接进入临界区域,减少等待时间(进入待机状态后,需要切换用户状态的内核状态,成本变大)。 主要意思是为了提高效率,分析什么是自旋。
临界区域API实现流程
InitialzeCriticalSection在初始化过程中测试CPU的数量。 如果CPU的数量为1,则忙碌的等待没有意义。 SpinCount=0,
当CPU数大于1时,设定SpinCount,进入临界区域时,积极采取进入战略。
EnterCriticalSection 1.如果关键节尚未被占用,请更新关键节的数据结构,指示调用线程可以访问关键节并返回。
2 .如果线程已经具有访问权限,则再次运行EnterCriticalSection将更新线程获得访问权限的次数,即连续运行Enter的次数。
3 .如果关键节已被其他线程占用,则当前线程将控制SpinCount繁忙的次数;如果SpinCount已经等于0且尚未获得关键节对象,则返回函数优先以旋转方式进入关键节,而不是直接通过关键节对象内部的事件对象等待(等待涉及用户状态和内核状态之间的切换)的最佳方法。 繁忙的等待时间通过对LockCount进行原子的读写操作来实现。
recursion count-- rtleavecriticalsection1. _ RTL _ critical _ section数据结构中的相关标志位设置,例如。 0表示线程不占用关键节
2 .将当前占用线程句柄设置为0,表示当前关键节当前处于信号状态,可以获取
3 .如果其他线程正在等待,则启动等待线程
从该数据结构可以看出,在过程中,所有临界区域的DEBUG信息都通过链表连接在一起。 知道某个临界区域的对象
时,可以通过链表中的数据结构访问数据的临界区域对象。
旋转:
对于临界区操作,(EnterCriticalSection )操作采用主动进入临界区。 也就是说,不能进入的时候,在进入之前会继续积极地尝试进入。 这种积极的进入方式叫做自旋。
被动方式:无法获取后,进入队列,待获取的对象释放后,系统唤醒等待线程的方式称为被动方式。
总结:
1 .进入灵界区和离开临界区是对操作,进入临界区必须离开临界区,否则临界区保护的共享资源永远不会释放。
2 .使用关键节时,希望缩短关键节中使用的代码,减少其他线程的等待时间,提高程序性能。
3 .关键节同步速度很快,但只能用于同步本进程中的线程,不能用于同步多个进程中的线程。
4 .关键部分是用户状态的对象,不是内核对象,所以不需要在用户状态和内核状态之间切换,明显比其他用户独占使用的内核对象效率更高。
参考: