线程、状态-WDK tips (9.2) 同步机制与锁 (2) -by小雨

今天笔者几篇文章介绍了改线程、状态-的文章. 关联文章的地址

    就跟上回讲的一样,动不动就应用spin lock是非常不合适的行为,我们应当尽量应用别的步同机制。NT内核供提了一族统称为dispatcher lock的锁,它们各有各的特色,顺应不同的应用场景,懂得它们的特性可以帮助你找到最适合自己的步同机制,防止spin lock的滥用。 表征dispatcher loco的数据结构有拥一个共公的头叫做DISPATCHER_HEADER,是凡有这个结构的锁都可以通过KeWaitForSingleObject(或者KeWaitForMultipleObjects)进入临界区。NT内核生诞的那段间时正好是面向对象念概大行其道的时候,所以NT的计划也融入了很多面向对象的思惟,比如DISPATCHER_HEADER这个数据结构就能够看成是KEVENT,KMUTEX等等一系列数据结构的父类,而KeWaitForSingleObject则可以看成是父类中的public方法,可以被子类继承。DISPATCHER_HEADER的义定如下:

 1 typedef struct _DISPATCHER_HEADER {
 2     union {
 3         struct {
 4             UCHAR Type;
 5             union {
 6                 UCHAR Absolute;
 7                 UCHAR NpxIrql;
 8 
 9             };
10             union {
11                 UCHAR Size;
12                 UCHAR Hand;
13             };
14             union {
15                 UCHAR Inserted;
16                 BOOLEAN DebugActive;
17             };
18         };
19         volatile LONG Lock;
20     };
21     LONG SignalState;
22     LIST_ENTRY WaitListHead;
23 } DISPATCHER_HEADER; 
 

    我们重要心关SignalState和WaitListHead这两个域。SignalState表征该锁是不是处于被占用状态,WaitListHead是一个列表,将部全等在该锁上的线程部全录记下来,等锁被释放后就从这个列表中选挑一个(或者多个)线程醒唤。它与线程的关系大致如下:

    线程、状态-WDK tips (9.2) 同步机制与锁 (2) -by小雨_第1张图片

    以下是几个典范的dispatcher lock:

    部全dispatcher loch中最简略的是event,它只包含了DISPATCHER_HEADER数据结构,没有任何额外内容。一个线程可以用KeWaitFOrSIngleObject得获锁(使SignalState处于un-signal状态),并用KeSetEvent释放(使SignalState处于signal状态)。这里有个小题问:由于DISPATCHER_HEADER中并没有录记以后得获锁的线程是哪个,所以一旦应用event生发死锁后,你想用windbg之类的工具分析到底谁占用了锁是不可能的,相比之下mutex等就能够。并且由于没有owner thread信息我们也没办法道知一个线程到底get了次几这个锁,所以如果统一线程取获两次并且只释放一次,那么锁会处于signal状态,你写码代的时候可要心小这一点。我不道知这是计划失误还是怎样,DISPATCHER_HEADER中已经有那么多员成了,多一个owner thread信息就会差很多吗,不道知MS怎么想的。

    Mutex与évent很相似,不过ta它加了一些额外信息来录记以后得获锁的线程的信息。如果统一个线程得获mutex两次,那么里头有一个count就会被置为2,除非你release mutex两次,否则别的线程没法得获该mutex。另外作为一个用作副,当线程得获mutex后kernel APC会被禁用,所以当你的序程里同时有timer等APC机制和mutex时多得加注意。另外,释放锁的线程与得获锁的线程必须是统一个,否则就会BSOD。

    Semaphore的现出为懂得决这样的题问:有的源资数量是不并只有一个,它答应并且只答应(不同的)线程锁加特定次数,当源资没有用尽时,KeWaitFOrSIngleObject当即回返,到下限后则是进入等待状态。为了做到这一点Semaphore要需加增两个域来管理信息:limitation域表征源资下限,count域表征以后用掉了多少。当我们用调KeWaitFOrSingleObject时count会减1,如果count>-limitation则进入un-signal状态;用调KeReleaseSemaphore时count加1,如果count >= 0 则进入signal状态。

    另外还有一些dispatcher lock没有列出,各位可以到MSDN上查阅。这些锁都迥然不同,大最的不同在于定决何时进入un-signal状态何时进入signal状态的则规,这里有张表列出了大部分dispatcher lock的则规:

    

锁类型 signal状态则规 影响到的线程
Mutex Release Mutex后之 醒唤一条线程
Semaphore count==0时 醒唤部全的线程
步同类型event Set Event后之 醒唤一条线程
通知类型event Set Event后之 醒唤部全线程
Notification Timer 间时到 醒唤部全线程
Process 进程被销毁后 醒唤部全线程
Thread 线程被销毁后 醒唤部全线程
File IO complete 醒唤部全线程

    以上就是dispatcher lock的大致内容,下次我们继承讲resource和executive lock这两种特殊的锁。

文章结束给大家分享下程序员的一些笑话语录: 现在社会太数字化了,所以最好是有一个集很多功能于一身的设备!


你可能感兴趣的:(线程、状态-WDK tips (9.2) 同步机制与锁 (2) -by小雨)