tman402
驱动牛犊
驱动牛犊
  • 注册日期2003-05-09
  • 最后登录2006-05-17
  • 粉丝0
  • 关注0
  • 积分25分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
阅读:2821回复:4

请问什么是“自旋锁”?

楼主#
更多 发布于:2004-03-04 20:45
请问什么是“自旋锁”?
seaquester
驱动大牛
驱动大牛
  • 注册日期2002-05-22
  • 最后登录2016-06-16
  • 粉丝0
  • 关注0
  • 积分500分
  • 威望115点
  • 贡献值0点
  • 好评度107点
  • 原创分0分
  • 专家分52分
沙发#
发布于: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。
八风舞遥翩,九野弄清音。 鸣高常向月,善舞不迎人。
seaquester
驱动大牛
驱动大牛
  • 注册日期2002-05-22
  • 最后登录2016-06-16
  • 粉丝0
  • 关注0
  • 积分500分
  • 威望115点
  • 贡献值0点
  • 好评度107点
  • 原创分0分
  • 专家分52分
板凳#
发布于: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的级上获取自旋锁,但你和我都做不到这一点。
八风舞遥翩,九野弄清音。 鸣高常向月,善舞不迎人。
nosegay
驱动牛犊
驱动牛犊
  • 注册日期2003-12-25
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-03-06 10:58
楼上的高手你好,请问,在何时需要向系统申请自旋锁,持有自旋锁的时间如何控制,谢谢!
bubblue
驱动牛犊
驱动牛犊
  • 注册日期2004-08-26
  • 最后登录2004-12-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于: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》希望都楼上的有帮助
游客

返回顶部