Critical Section 对象
关键节对象 提供类似于互斥体对象提供的同步,但关键节只能由单个进程的线程使用。 关键节对象不能跨进程共享。
事件、互斥体和信号灯对象也可以在单进程应用程序中使用,但关键节对象为相互排斥同步(处理器特定的测试和设置指令)提供了一种略快、更高效的机制。 与互斥对象一样,关键节对象一次只能由一个线程拥有,这使得它可用于保护共享资源免受同时访问。 与互斥体对象不同,无法判断关键节是否已放弃。
从具有 Service Pack 1(SP1)的 Windows Server 2003 开始,等待关键部分的线程不会首先获取关键部分。 此更改可显著提高大多数代码的性能。 但是,某些应用程序依赖于先入先出(FIFO)排序,在当前版本的 Windows(例如,使用关键节作为速率限制器的应用程序)上可能表现不佳或根本不执行。 若要确保代码继续正常运行,可能需要添加额外的同步级别。 例如,假设你有一个生成者线程和一个使用者线程,该线程使用关键节对象来同步其工作。 创建两个事件对象,每个线程一个用于指示它已准备好让另一个线程继续。 使用者线程将等待生成者在进入关键节之前向事件发出信号,生成者线程将等待使用者线程在进入关键节之前对其事件发出信号。 每个线程离开关键部分后,它会向事件发出释放另一个线程的信号。
Windows Server 2003 和 Windows XP: 正在等待关键部分的线程添加到等待队列;它们已唤醒,通常按照添加到队列的顺序获取关键部分。 但是,如果线程以足够快的速度添加到此队列,性能可能会下降,因为唤醒每个等待线程所需的时间。
此过程负责分配关键部分使用的内存。 通常,只需声明类型为 CRITICAL_SECTION的变量即可完成此作。 在进程线程可以使用之前,请使用 InitializeCriticalSection 或 InitializeCriticalSectionAndSpinCount 函数初始化关键节。
线程使用 EnterCriticalSection 或 TryEnterCriticalSection 函数请求关键部分的所有权。 它使用 LeaveCriticalSection 函数释放关键部分的所有权。 如果关键节对象当前属于另一个线程,EnterCriticalSection 无限期等待所有权。 相比之下,当互斥体对象用于相互排除时,等待函数 接受指定的超时间隔。 TryEnterCriticalSection 函数尝试输入关键节,而不会阻止调用线程。
当线程拥有关键节时,它可以对 EnterCriticalSection 或 TryEnterCriticalSection 进行其他调用,而不会阻止其执行。 这样可以防止线程在等待它已拥有的关键部分时自行死锁。 若要释放其所有权,线程必须在每次进入关键节时调用 LeaveCriticalSection 一次。 无法保证等待线程获取关键部分的所有权的顺序。
线程使用 InitializeCriticalSectionAndSpinCount 或 SetCriticalSectionSpinCount 函数指定关键节对象的旋转计数。 旋转意味着当线程尝试获取锁定的关键部分时,线程将进入循环,检查锁是否已释放,以及锁是否未释放,线程进入睡眠状态。 在单处理器系统上,将忽略旋转计数,关键节旋转计数设置为 0(零)。 在多处理器系统上,如果关键部分不可用,调用线程会在与关键节关联的信号灯上执行等待作之前 dwSpinCount 次旋转。 如果在旋转作期间关键部分变得空闲,则调用线程将避免等待作。
进程的任何线程都可以使用 DeleteCriticalSection 函数释放初始化关键节对象时分配的系统资源。 调用此函数后,关键节对象不能用于同步。
拥有关键节对象时,唯一受影响的其他线程是在调用 EnterCriticalSection中等待所有权的线程。 未等待的线程可以继续运行。
相关主题