内核同步对象下.doc

内核同步对象 下 ? 内核同步对象(下)2010-06-03 16:41互斥(mutex)就是互相排斥(mutual exclusion)的简写。内核互斥对象为多个竞争线程串行化访问共享资源提供了一种方法(不一定是最好的方法)。如果互斥对象不被某线程所拥有,则它是信号态,反之则是非信号态。当线程为了获得互斥对象的控制权而调用KeWaitXxx例程时,内核同时也做了一些工作以帮助避免可能的死锁。同样,互斥对象也需要与KeWaitForSingleObject类似的附加动作。内核可以确保线程不被换出,并且阻止所有APC的提交,内核专用APC(如IoCompleteRequest用以完成I/O请求的APC)除外。 通常我们应该使用executive部件输出的快速互斥对象而不是内核互斥对象。这两者的主要不同是,内核互斥可以被递归获取,而executive快速互斥则不能。即内核互斥的所有者可以调用KeWaitXxx并指定所拥有的互斥对象从而使等待立即被满足。如果一个线程真的这样做,它必须也要以同样的次数释放该互斥对象,否则该互斥对象不被认为是空闲的。 如果你需要长时间串行化访问一个对象,你应该首先考虑使用互斥(而不是依赖提升的IRQL和自旋锁)。利用互斥对象控制资源的访问,可以使其它线程分布到多处理器平台上的其它CPU中运行,还允许导致页故障的代码仍能锁定资源而不被其它线程访问。表4-4列出了互斥对象的服务函数。 表4-4.互斥对象服务函数 服务函数描述 KeInitializeMutex初始化互斥对象 KeReadStateMutex取互斥对象的当前状态 KeReleaseMutex设置互斥对象为信号态 为了创建一个互斥对象,你需要为KMUTEX对象保留一块非分页内存,然后象下面这样初始化: ASSERT(KeGetCurrentIrql()==PASSIVE_LEVEL); KeInitializeMutex(mutex,level); mutex是KMUTEX对象的地址,level参数最初是用于辅助避免多互斥对象带来的死锁。但现在,内核忽略level参数。 互斥对象的初始状态为信号态,即未被任何线程拥有。KeWaitXxx调用将使调用者接管互斥对象的控制并使其进入非信号态。 利用下面函数可以获取互斥对象的当前状态: ASSERT(KeGetCurrentIrql()=DISPATCH_LEVEL); LONG signalled=KeReadStateMutex(mutex); 返回值0表示互斥对象已被占用,非0表示未被占用。 下面函数可以使所有者放弃其占有的互斥对象并使其进入信号态: ASSERT(KeGetCurrentIrql()==PASSIVE_LEVEL); LONG wassignalled=KeReleaseMutex(mutex,wait); wait参数与KeSetEvent函数中的含义相同。该函数返回值总是0,表示该互斥对象曾被占用过,如果不是这种情况(所有者释放的不是它自己的对象),KeReleaseMutex将产生bug check。 出于完整性的考虑,我想提一下KeWaitForMutexObject函数,它是DDK中的宏(见WDM.H)。其定义如下: #define KeWaitForMutexObject KeWaitForSingleObject 内核定时器 内核还提供了一种定时器对象,该对象可以在指定的绝对时间或间隔时间后自动从非信号态变为信号态。它还可以周期性地进入信号态。我们可以用它来安排一个定期执行的DPC回调函数。表4-5列出了用于定时器对象的服务函数。 表4-5.内核定时器对象的服务函数 服务函数描述 KeCancelTimer取消一个活动的定时器 KeInitializeTimer初始化一次性的通知定时器 KeInitializeTimerEx初始化一次性的或重复通知的或同步的定时器 KeReadStateTimer获取定时器的当前状态 KeSetTimer为通知定时器设定时间 KeSetTimerEx为定时器设定时间和其它属性 通知定时器用起来象事件 在这一段中,我们将创建一个通知定时器对象并等到它达到预定时间。首先,我们在非分页内存中分配一个KTIMER对象。然后,我们在低于或等于DISPATCH_LEVEL级上初始化这个定时器对象: PKTIMER timer;//someone gives you this ASSERT(KeGetCurrentIrql()=DISPATCH_LEVEL); KeInitializeTimer(timer); 在此,定时器处于非信号状态,它还没有开始倒计时,在这样的定时器上等待的线程永远得不到唤醒。为了启动定时器倒计时,我们调用KeSetTi

文档评论(0)

1亿VIP精品文档

相关文档