自旋锁简介
旋转锁是内核定义的仅限内核模式的同步机制,导出为不透明类型:KSPIN_LOCK。 旋转锁可用于保护共享数据或资源免受同时访问。 在 IRQL <= DISPATCH_LEVEL运行时,驱动程序可以使用 KeAcquireInStackQueuedSpinLock 和 KeReleaseInStackQueuedSpinLock 获取并释放旋转锁作为排队旋转锁。
或者,在 IRQL >= DISPATCH_LEVEL运行的调用方可以调用 KeAcquireSpinLockAtDpcLevel 和 KeReleaseSpinLockFromDpcLevel 以提高驱动程序性能。
许多组件使用旋转锁,包括驱动程序。 任何类型的驱动程序都可能使用一个或多个 执行旋转锁。 例如,大多数文件系统使用文件系统驱动程序(FSD)设备扩展中的联锁工作队列来存储由文件系统的工作线程回调例程和 FSD 处理的 IRP。 联锁工作队列受执行旋转锁的保护,该锁可解析 FSD 尝试将 IRP 插入队列中的争用,以及同时尝试删除 IRP 的任何线程。 作为另一个示例,系统软盘控制器驱动程序使用两个执行旋转锁。 一个执行旋转锁保护与此驱动程序的设备专用线程共享的已锁工作队列;另一个保护由三个驱动程序例程共享的计时器对象。
排队旋转锁比多处理器计算机上的高争用锁的普通旋转锁提供更好的性能。 有关详细信息,请参阅 排队旋转锁。 驱动程序还可以使用 KeAcquireSpinLock 和 KeReleaseSpinLock 获取和释放旋转锁作为普通旋转锁。
若要同步对简单数据结构的访问,驱动程序可以使用任何 ExInterlockedXxx 例程来确保对数据结构的原子访问。 使用这些例程的驱动程序不需要显式获取或释放旋转锁。
拥有 ISR 的每个驱动程序都使用中断旋转锁来保护其 ISR 与其 SynchCritSection 例程之间共享的任何数据或硬件,这些例程通常从 StartIo 和 DpcForIsr 例程中调用。 中断旋转锁与驱动程序调用 Io连接Interrupt 时创建的中断对象集相关联,如注册 ISR 中所述。
按照以下准则在驱动程序中使用旋转锁:
为受旋转锁保护的任何数据或资源以及驻留系统空间内存(非分页池)中的相应旋转锁(如虚拟内存空间和物理内存图中所示)提供存储。 驱动程序必须为它使用的任何执行旋转锁提供存储。 但是,设备驱动程序不需要为中断旋转锁提供存储,除非它具有多维函数 ISR 或具有多个 ISR,如注册 ISR 中所述。
调用 KeInitializeSpinLock 以初始化驱动程序为其提供存储的每个旋转锁,然后再使用它来同步对所保护的共享数据或资源的访问。
在适当的 IRQL 上调用使用旋转锁的每个支持例程,通常为 <= 执行旋转锁DISPATCH_LEVEL,或者调用 <与驱动程序中断对象关联的中断旋转锁的 DIRQL。
实现例程,以便在它们按住旋转锁时尽快执行。 任何例程都不应持有超过 25 微秒的旋转锁。
切勿实现在按住旋转锁时执行以下任一操作的例程:
导致硬件异常或引发软件异常。
尝试访问可分页内存。
进行递归调用,导致死锁或可能导致旋转锁保留超过 25 微秒。
如果这样做可能会导致死锁,则尝试获取另一个旋转锁。
调用违反上述任何规则的外部例程。