临界区对象

临界区对象 提供与 mutex 对象提供的同步,只不过临界区只能由单个进程的线程使用。 不能跨进程共享临界区对象。

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

从带有 Service Pack 1 (SP1) 的 Windows Server 2003 开始,在关键部分上等待的线程不会按首先服务的基础获取关键部分。 对于大多数代码,此更改会显著提高性能。 但是,某些应用程序依赖于先进先出 (FIFO) 顺序,并且可能会在当前版本的 Windows 上性能低下或根本不执行 (例如,使用关键部分作为限制实现限制) 的应用程序。 若要确保代码继续正常工作,可能需要添加其他级别的同步。 例如,假设你有一个生成者线程,以及一个使用关键部分对象来同步其工作的使用者线程。 创建两个事件对象,每个线程用于表示它已准备就绪,可供其他线程继续。 在进入临界区之前,使用者线程将等待制造者向其发出信号,而制造者线程将等待使用者线程在进入临界区之前通知其事件。 每个线程离开临界区后,会向其发出信号,指示其事件释放另一个线程。

Windows Server 2003 和 WINDOWS XP: 正在等待临界区的线程添加到等待队列;它们是唤醒的,通常按其添加到队列中的顺序获取关键部分。 但是,如果线程以足够快的速度添加到此队列中,则可能会由于唤醒每个等待线程所需的时间而降低性能。

该进程负责分配关键部分使用的内存。 通常,这是通过只声明类型为 " 关键 _" 的变量来完成的。 在进程的线程可以使用它之前,请使用 InitializeCriticalSectionInitializeCriticalSectionAndSpinCount 函数初始化临界区。

线程使用 EnterCriticalSectionTryEnterCriticalSection 函数请求关键部分的所有权。 它使用 LeaveCriticalSection 函数释放关键部分的所有权。 如果临界区对象当前由另一个线程拥有,则 EnterCriticalSection 会无限期地等待所有权。 相反,当 mutex 对象用于相互排除时, 等待函数 将接受指定的超时间隔。 TryEnterCriticalSection 函数尝试输入临界区,而不会阻止调用线程。

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

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

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

当拥有临界区对象时,受影响的其他线程只是在对 EnterCriticalSection的调用中等待所有权的线程。 未等待的线程可以继续运行。

互斥对象

使用临界区对象