在 DPC 中使用唯一锁

Using unique locks while in DPC

目前正在研究 NDIS 堆栈中的轻量级过滤器。我正在尝试注入一个在全局变量中设置为 NBL 的数据包。在接收 NBL 期间,如果注入的 NBL 处于挂起状态,则线程会在选取注入的 NBL 进行处理之前获取锁。最初我正在考虑使用自旋锁或 FAST_MUTEX。但是根据 FAST_MUTEX 的文档,任何其他尝试获取锁的线程都将等待锁释放后再继续。

问题是,在 DPC 模式下接收 NBL 是 运行。这将导致 DPC 运行 线程暂停并等待锁释放。此外,我希望能够断言线程对锁的所有权。

我的问题是,windows 内核是否支持内核中的唯一互斥锁,这些锁是否可以在 DPC 模式下获取以及锁中所有权的断言有多昂贵。我是 C++ 的新手,所以请原谅任何语法错误。

我试图在 LWF 对象中定义互斥体

// Header file

#pragma once
#include <mutex.h>

class LWFobject
{
public:
  LWFobject()
  std::mutex ExampleMutex;
  std::unique_lock ExampleLock;
}

//=============================================
// CPP file
#include "LWFobject.h"

LWFobject::LWFObject()
{
  ExmapleMutex = CreateMutex( 
        NULL,
        FALSE,    
        NULL); 
  ExampleLock(ExampleMutex, std::defer_lock);
}

内核是否支持使用unique_locks?当我尝试编译它时,它会在尝试使用 mutex.h 时抛出数百个编译错误。我想使用 try_lockowns_lock

您不能在 Windows 内核中使用标准 ISO C++ 同步机制。

一个 Windows 内核本身就是另一个世界,需要您遵守它的规则(这些规则非常广泛 - 例如参见这两本 700 页的书:1, 2)。

Windows 内核内部的处理主要是异步和基于事件的;您处理事件并安排延迟调用或使用其他 synchronization techniques 来完成需要稍后完成的工作。

话虽如此, 可以在 Windows 驱动程序中使用传统意义上的互斥体。就叫一个Fast Mutex and requires raising IRQL to APC_LEVEL. Then you can use calls like ExAcquireFastMutex, ExTryToAcquireFastMutex and ExReleaseFastMutex到lock/try-lock/release吧。

锁的基本 属性 是它同步的优先级 (IRQL)。可以从低优先级获得锁,但永远不能从高优先级获得。

(为什么?想象一下锁是如何实现的。锁必须将当前任务的优先级提高到锁的自然优先级。如果它不这样做,那么任务 运行ning 会处于低priority 可以获取锁,被更高优先级的任务抢占,如果它试图获取相同的锁就会死锁。所以每个锁都有一个记录的自然 IRQL,锁将首先将当前线程提升到该 IRQL在尝试获得排他性之前。)

NDIS 数据路径可以 运行 在 PASSIVE_LEVEL 和 DISPATCH_LEVEL 之间的任何 IRQL,包括在内。这意味着数据路径上的任何内容都只能使用在 DISPATCH_LEVEL(或更高)同步的锁。这确实限制了您的选择:您可以使用 KSPIN_LOCKs、NDIS_RW_LOCKs 和其他一些不常用的选项。

这变得病毒式传播:如果你有一个函数有时可以 运行 在 DISPATCH_LEVEL(比如数据路径),它会强制锁在 DISPATCH_LEVEL 同步,这会强制在 DISPATCH_LEVEL 处也持有 运行 锁的任何其他函数。这可能会带来不便,例如,您可能还想在从注册表中读取数据时保持锁定。

有多种方法可以设计您的驱动程序: * 到处使用自旋锁。从注册表读取时,读入临时变量,然后获取自旋锁并将临时变量复制到全局状态。 * 到处使用互斥锁(或者更好的是:推锁)。将数据路径隔离到 运行 分派级别的组件中,并小心地将任何配置状态复制到该组件的私有状态中。 * 以某种方式避免让您的数据路径与您的驱动程序的其余部分交互,因此没有共享状态,因此没有共享锁。 * 通过将所有数据包排队到工作线程,让数据路径快速到达 PASSIVE_LEVEL。