关键节对象

关键节对象提供的同步类似于互斥对象提供的同步,只不过关键节只能由单个进程的线程使用。 关键节对象不能跨进程共享。

事件、互斥体和信号灯对象也可以在单进程应用程序中使用,但关键部分对象为互斥同步提供了一种略快、更高效的机制, (特定于处理器的测试并设置指令) 。 与互斥对象一样,关键节对象一次只能由一个线程拥有,这使得它可用于保护共享资源免受同时访问。 与互斥对象不同,无法判断关键部分是否已放弃。

从 Windows Server 2003 Service Pack 1 (SP1) 开始,在关键节上等待的线程不会先到先得地获取关键部分。 此更改可显著提高大多数代码的性能。 但是,某些应用程序依赖于先入先出 (FIFO) 排序,在当前版本的 Windows ((例如,使用关键部分作为速率限制器) 的应用程序)上性能不佳或根本没有性能。 若要确保代码继续正常工作,可能需要添加额外的同步级别。 例如,假设你有一个生成者线程和一个使用关键节对象来同步其工作的使用者线程。 创建两个事件对象,每个线程各一个,用于指示它已准备好让另一个线程继续。 使用者线程将在进入关键部分之前等待生成者发出事件信号,生成者线程将等待使用者线程发出其事件信号,然后再进入关键部分。 每个线程离开关键部分后,它会向事件发出信号以释放另一个线程。

Windows Server 2003 和 Windows XP: 正在关键节上等待的线程将添加到等待队列;它们被唤醒,通常按添加到队列的顺序获取关键节。 但是,如果线程以足够快的速度添加到此队列,则性能可能会降低,因为唤醒每个等待线程所需的时间。

进程负责分配关键节使用的内存。 通常,只需声明 CRITICAL_SECTION 类型的变量即可完成此操作。 在进程的线程可以使用它之前,请使用 InitializeCriticalSection 或 InitializeCriticalSectionAndSpinCount 函数初始化关键节。

线程使用 EnterCriticalSectionTryEnterCriticalSection 函数请求关键节的所有权。 它使用 LeaveCriticalSection 函数释放关键节的所有权。 如果关键节对象当前由另一个线程拥有, 则 EnterCriticalSection 将无限期等待所有权。 相比之下,当互斥对象用于互斥时, 等待函数 接受指定的超时间隔。 TryEnterCriticalSection 函数尝试在不阻止调用线程的情况下进入关键部分。

当线程拥有关键节时,它可以对 EnterCriticalSectionTryEnterCriticalSection 进行其他调用,而不会阻止其执行。 这可以防止线程在等待它已拥有的关键节时自行死锁。 若要释放其所有权,线程必须在每次进入关键部分时调用 一次 LeaveCriticalSection 。 无法保证等待线程获取关键节所有权的顺序。

线程使用 InitializeCriticalSectionAndSpinCountSetCriticalSectionSpinCount 函数指定关键节对象的旋转计数。 旋转意味着当线程尝试获取锁定的关键部分时,线程进入循环,检查是否释放锁,如果锁未释放,线程将进入睡眠状态。 在单处理器系统上,将忽略旋转计数,并将关键部分旋转计数设置为 0 (零) 。 在多处理器系统上,如果关键部分不可用,则调用线程在对与关键部分关联的信号灯执行等待操作之前,将旋转 dwSpinCount 次。 如果关键部分在旋转操作期间变为空闲,调用线程将避免等待操作。

进程的任何线程都可以使用 DeleteCriticalSection 函数释放在初始化关键节对象时分配的系统资源。 调用此函数后,不能使用关键节对象进行同步。

当拥有关键节对象时,唯一受影响的其他线程是在调用 EnterCriticalSection 时等待所有权的线程。 未等待的线程可以自由地继续运行。

互斥对象

使用关键节对象