倪勋的专栏

智慧和勇气,人生的两个财富

用户操作
[即时聊天] [发私信] [加为好友]
倪勋ID:nixun
17018次访问,排名7320(-1),好友0人,关注者0人。
nixun的文章
原创 13 篇
翻译 0 篇
转载 6 篇
评论 6 篇
nixun的公告
最近评论
crunch:Sorry, ExMinimumLookasideDepth 确实为4
crunch:但这个深度从不低于4,这也是新链表的初始深度。
这个说法在Win2003的源代码中看到的不一致.
Lookaside->L.Depth = ExMinimumLookasideDepth;
Lookaside->L.MaximumDepth = 256; //Depth;

DriverUnload只是在DriverEntry返回……
woaipinkfloyd:怎么没有提供答案
想学习学习
maleo:不错的说!!!!
最快的排序?
好像有o(n)的吧
radix sort
siso:请问目前哪种排序速度最快,是否快速排序?
文章分类
收藏
    相册
    个人blog链接
    Jerry
    johnny
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 自旋锁收藏

    新一篇: IRP | 旧一篇: 中断请求级

    [返回] [上一页] [下一页]

    自旋锁


    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的级上获取自旋锁,但你和我都做不到这一点。

     

    使用自旋锁

    为了明确地使用一个自旋锁,首先要在非分页内存中为一个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
    }
    1. KeAcquireSpinLock获取自旋锁时,它也把IRQL提升到DISPATCH_LEVEL级上。
    2. KeReleaseSpinLock释放自旋锁时,它也把IRQL降低到原来的IRQL级上。

    如果你知道代码已经处在DISPATCH_LEVEL级上,你可以调用两个专用函数来获取自旋锁。这个技术适合于DPC、StartIo,和其它执行在DISPATCH_LEVEL级上的驱动程序例程:

    KeAcquireSpinLockAtDpcLevel(&pdx->QLock);
    ...
    KeReleaseSpinLockFromDpcLevel(&pdx->QLock);
     

    发表于 @ 2007年11月27日 21:35:00|评论(loading...)|编辑

    新一篇: IRP | 旧一篇: 中断请求级

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © nixun