阅读:2821回复:4
请问什么是“自旋锁”?
请问什么是“自旋锁”?
|
|
沙发#
发布于:2004-03-05 08:48
请问什么是“自旋锁”? SpinLock(自旋锁)是用于解决多CPU上面的同步问题的一种机制。 A spin lock can be used to protect shared data or resources from simultaneous access by routines that can execute concurrently and at raised IRQL in SMP machines。 |
|
|
板凳#
发布于:2004-03-05 08:51
[quote]请问什么是“自旋锁”? SpinLock(自旋锁)是用于解决多CPU上面的同步问题的一种机制。 A spin lock can be used to protect shared data or resources from simultaneous access by routines that can execute concurrently and at raised IRQL in SMP machines。 [/quote] 下面的文字摘自Walter Oney的《Programming The Microsoft Windows Driver Model》: IRQL概念仅能解决单CPU上的同步问题,在多处理器平台上,它不能保证你的代码不被运行在其它处理器上的代码所干扰。一个称为自旋锁(spin lock)的原始对象可以解决这个问题。为了获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其它CPU不可能访问这个内存变量。如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行。如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置(test-and-set)”操作,即开始“自旋”。最后,锁的所有者通过重置该变量释放这个自旋锁,于是,某个等待的test-and-set操作向其调用者报告锁已释放。 关于自旋锁有两个明显的事实。第一,如果一个已经拥有某个自旋锁的CPU想第二次获得这个自旋锁,则该CPU将死锁(deadlock)。自旋锁没有与其关联的“使用计数器”或“所有者标识”;锁或者被占用或者空闲。如果你在锁被占用时获取它,你将等待到该锁被释放。如果碰巧你的CPU已经拥有了该锁,那么用于释放锁的代码将得不到运行,因为你使CPU永远处于“测试并设置”某个内存变量的自旋状态。 关于自旋锁的另一个事实是,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待。所以,为了避免影响性能,你应该在拥有自旋锁时做尽量少的操作,因为此时某个CPU可能正在等待这个自旋锁。 关于自旋锁还存在着一个不太明显但很重要的事实:你仅能在低于或等于DISPATCH_LEVEL级上请求自旋锁,在你拥有自旋锁期间,内核将把你的代码提升到DISPATCH_LEVEL级上运行。在内部,内核能在高于DISPATCH_LEVEL的级上获取自旋锁,但你和我都做不到这一点。 |
|
|
地板#
发布于:2004-03-06 10:58
楼上的高手你好,请问,在何时需要向系统申请自旋锁,持有自旋锁的时间如何控制,谢谢!
|
|
地下室#
发布于:2004-08-26 18:24
为了明确地使用一个自旋锁,首先要在非分页内存中为一个KSPIN_LOCK对象分配存储。然后调用KeInitializeSpinLock初始化这个对象。接着,当代码运行在低于或等于DISPATCH_LEVEL级上时获取这个锁,并执行需要保护的代码,最后释放自旋锁。例如,假设你的设备扩展中有一个名为QLock的自旋锁,你用它来保护你专用IRP队列的访问。你应该在AddDevice函数中初始化这个锁:
typedef struct _DEVICE_EXTENSION { ... KSPIN_LOCK QLock; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; ... NTSTATUS AddDevice(...) { ... PDEVICE_EXTENSION pdx = ...; KeInitializeSpinLock(&pdx->QLock); ... } 在驱动程序的其它地方,假定就在某种IRP的派遣函数中,你在某些必须的队列操作代码周围获取了(并很快释放)该自旋锁。注意这个函数必须存在于非分页内存中,因为在某个时期它会执行在提升的IRQL上。 NTSTATUS DispatchSomething(...) { KIRQL oldirql; PDEVICE_EXTENSION pdx = ...; KeAcquireSpinLock(&pdx->QLock, &oldirql); <--1 ... KeReleaseSpinLock(&pdx->QLock, oldirql); <--2 } 当KeAcquireSpinLock获取自旋锁时,它也把IRQL提升到DISPATCH_LEVEL级上。 当KeReleaseSpinLock释放自旋锁时,它也把IRQL降低到原来的IRQL级上。 如果你知道代码已经处在DISPATCH_LEVEL级上,你可以调用两个专用函数来获取自旋锁。这个技术适合于DPC、StartIo,和其它执行在DISPATCH_LEVEL级上的驱动程序例程: KeAcquireSpinLockAtDpcLevel(&pdx->QLock); ... KeReleaseSpinLockFromDpcLevel(&pdx->QLock); ----摘自《MSWDM》希望都楼上的有帮助 |
|