当前位置: 首页 > article >正文

Windows 驱动开发中 ExAcquireResourceExclusiveLite 和其他锁的区别:

1 Windows 驱动开发中 ExAcquireResourceExclusiveLite 和其他锁的区别

1. ExAcquireResourceExclusiveLite(独占资源锁)
特点:
- 是一种读写锁(ERESOURCE)的独占模式
- 同一时间只允许一个线程获得锁
- 可以递归获取(同一线程可以多次获取)
- 支持等待和超时机制
- 适用于内核模式代码
- 可以与共享锁(ExAcquireResourceSharedLite)配合使用

2. ExAcquireResourceSharedLite(共享资源锁)
特点:
- 同一时间允许多个线程以共享方式访问资源
- 与独占锁互斥
- 也支持递归获取
- 适合读多写少的场景

3. KeAcquireSpinLock(自旋锁)
特点:
- 轻量级锁,适合短时间持有
- 不会引起线程调度
- 占用CPU进行自旋等待
- 不能递归获取
- IRQL 限制较严格

4. FastMutex(快速互斥体)
特点:
- 比自旋锁更适合长时间持有
- 会引起线程调度(阻塞等待)
- 不能递归获取
- IRQL 限制相对宽松

5. KeWaitForMutexObject(互斥体)
特点:
- 可以在线程间同步
- 支持递归获取
- 会引起线程调度
- 可以跨进程使用

使用场景比较:

1. ExAcquireResourceExclusiveLite 适用于:
- 需要读写保护的复杂数据结构
- 可能长时间持有锁的场景
- 需要读写锁语义的场景
- 需要递归获取锁的场景

2. 自旋锁适用于:
- 极短时间的同步
- 不允许休眠的高 IRQL 环境
- 简单的原子操作保护

3. FastMutex 适用于:
- 中等时间的同步
- 不需要递归获取
- 允许线程调度的场景

4. 互斥体适用于:
- 长时间的同步
- 需要跨进程同步
- 需要递归获取
- 允许线程调度的场景

代码示例:

```c
// 资源锁使用示例
ERESOURCE Resource;
ExInitializeResourceLite(&Resource);

// 独占方式获取
ExAcquireResourceExclusiveLite(&Resource, TRUE);
// 临界区代码
ExReleaseResourceLite(&Resource);

// 共享方式获取
ExAcquireResourceSharedLite(&Resource, TRUE);
// 临界区代码
ExReleaseResourceLite(&Resource);

// 自旋锁使用示例
KSPIN_LOCK SpinLock;
KIRQL OldIrql;
KeInitializeSpinLock(&SpinLock);

KeAcquireSpinLock(&SpinLock, &OldIrql);
// 临界区代码
KeReleaseSpinLock(&SpinLock, OldIrql);

// FastMutex 使用示例
FAST_MUTEX FastMutex;
ExInitializeFastMutex(&FastMutex);

ExAcquireFastMutex(&FastMutex);
// 临界区代码
ExReleaseFastMutex(&FastMutex);
```

性能考虑:
1. 资源锁开销较大,但功能最完整
2. 自旋锁开销最小,但功能有限
3. FastMutex 介于两者之间
4. 互斥体开销较大,但跨进程同步能力强

选择建议:
1. 如果需要读写锁语义,选择 ERESOURCE
2. 如果是短时间同步,选择自旋锁
3. 如果是中等时间同步且不需要递归,选择 FastMutex
4. 如果需要跨进程同步,选择互斥体
 

2 具体使用场合和 IRQL 限制:

1. ExAcquireResourceExclusiveLite (ERESOURCE)
IRQL 限制:
- 必须 < DISPATCH_LEVEL (最高 APC_LEVEL)
- 获取锁时可能会休眠

使用场合:
```c
// 适用于复杂数据结构的保护
typedef struct _DEVICE_EXTENSION {
    ERESOURCE DeviceResource;
    LIST_ENTRY PendingIoQueue;
    // ... 其他成员
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

// 初始化
ExInitializeResourceLite(&deviceExtension->DeviceResource);

// 在 IRP 处理中使用
NTSTATUS HandleIoRequest(PDEVICE_EXTENSION DevExt)
{
    // 可以在 PASSIVE_LEVEL 使用
    ExAcquireResourceExclusiveLite(&DevExt->DeviceResource, TRUE);
    
    InsertTailList(&DevExt->PendingIoQueue, &newRequest->ListEntry);
    
    ExReleaseResourceLite(&DevExt->DeviceResource);
    return STATUS_SUCCESS;
}
```

2. KeSpinLock
IRQL 限制:
- 可在任何 IRQL 级别获取
- 获取后提升到 DISPATCH_LEVEL
- 持有期间不能调用可能休眠的函数

使用场合:
```c
// 适用于中断处理和短期同步
typedef struct _DEVICE_CONTEXT {
    KSPIN_LOCK SpinLock;
    ULONG Counter;
    // ... 其他需要快速访问的数据
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;

VOID InterruptHandler(PDEVICE_CONTEXT Context)
{
    KIRQL oldIrql;
    // 可以在高 IRQL 使用
    KeAcquireSpinLock(&Context->SpinLock, &oldIrql);
    
    Context->Counter++;
    // 快速操作,不要有复杂处理
    
    KeReleaseSpinLock(&Context->SpinLock, oldIrql);
}
```

3. FastMutex
IRQL 限制:
- 必须 <= APC_LEVEL
- 获取时会禁用 APC
- 不能在中断处理中使用

使用场合:
```c
// 适用于中等复杂度的数据保护
typedef struct _QUEUE_MANAGER {
    FAST_MUTEX QueueLock;
    LIST_ENTRY Queue;
    ULONG QueueSize;
} QUEUE_MANAGER, *PQUEUE_MANAGER;

VOID ProcessQueue(PQUEUE_MANAGER QueueMgr)
{
    // 在普通驱动例程中使用
    ExAcquireFastMutex(&QueueMgr->QueueLock);
    
    if (!IsListEmpty(&QueueMgr->Queue)) {
        // 处理队列
        QueueMgr->QueueSize--;
    }
    
    ExReleaseFastMutex(&QueueMgr->QueueLock);
}
```

4. Mutex Object (KeWaitForMutexObject)
IRQL 限制:
- 必须 = PASSIVE_LEVEL
- 可能导致线程休眠

使用场合:
```c
// 适用于需要长时间同步的场景
VOID LongRunningOperation(PDEVICE_EXTENSION DevExt)
{
    // 只能在 PASSIVE_LEVEL 使用
    KeWaitForMutexObject(
        &DevExt->Mutex,
        Executive,
        KernelMode,
        FALSE,
        NULL
    );
    
    // 可以执行长时间操作
    // 可以调用可能休眠的函数
    
    KeReleaseMutex(&DevExt->Mutex, FALSE);
}
```

具体场景选择指南:

1. 中断处理程序 (ISR):
```c
// 只能使用自旋锁
VOID ISR(...)
{
    KIRQL oldIrql;
    KeAcquireSpinLock(&SpinLock, &oldIrql);
    // 快速处理
    KeReleaseSpinLock(&SpinLock, oldIrql);
}
```

2. DPC 例程:
```c
// 可以使用自旋锁
VOID DpcRoutine(...)
{
    // 已经在 DISPATCH_LEVEL
    KeAcquireSpinLockAtDpcLevel(&SpinLock);
    // 处理
    KeReleaseSpinLockFromDpcLevel(&SpinLock);
}
```

3. 普通驱动例程:
```c
// 可以使用所有类型的锁
NTSTATUS DriverRoutine(...)
{
    // 根据需求选择合适的锁
    if (简单快速操作) {
        // 使用自旋锁
        KeAcquireSpinLock(...);
    } else if (中等复杂度操作) {
        // 使用 FastMutex
        ExAcquireFastMutex(...);
    } else if (复杂操作需要读写锁) {
        // 使用 ERESOURCE
        ExAcquireResourceExclusiveLite(...);
    }
}
```

IRQL 限制总结:

1. ERESOURCE:
- 获取:< DISPATCH_LEVEL
- 释放:= 获取时的 IRQL

2. SpinLock:
- 获取:任何 IRQL
- 持有:DISPATCH_LEVEL
- 释放:恢复到之前的 IRQL

3. FastMutex:
- 获取:<= APC_LEVEL
- 持有:APC_LEVEL
- 释放:恢复到之前的 IRQL

4. Mutex Object:
- 获取:PASSIVE_LEVEL
- 持有:PASSIVE_LEVEL
- 释放:PASSIVE_LEVEL

选择建议:
1. 如果在高 IRQL(如中断):只能用自旋锁
2. 如果操作快速且简单:优先考虑自旋锁
3. 如果需要休眠或长时间操作:使用 ERESOURCE 或 Mutex Object
4. 如果需要读写锁语义:使用 ERESOURCE
5. 如果是中等复杂度操作:考虑 FastMutex
 


http://www.kler.cn/a/406302.html

相关文章:

  • Unable to find image ‘hello-world:latest‘ locally
  • Day24 回溯算法part03
  • 为什么transformer的时间复杂度是N的平方,具体是里面的哪一个计算流程最占用时间
  • Linux第96步_Linux中的宏DIV_ROUND_UP和BITS_TO_LONGS
  • element-plus的组件数据配置化封装 - table
  • python常用的排序算法
  • Windows中指定路径安装DockerDesktop
  • 死锁相关习题 10道 附详解
  • Day 18
  • 04高可用高并发(D1_高并发 - D1_缓存)
  • ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
  • 设计模式之 状态模式
  • WonderJourney 部署踩坑笔记 2024 ok
  • Java方法中的可变参数列表
  • 【C#】面向对象:矩形类计算周长和面积
  • 【java-Neo4j 5开发入门篇】-最新Java开发Neo4j
  • 《OpenCV 图像缩放、翻转与变换全攻略:从基础操作到高级应用实战》
  • 考虑楼宇空间布局的电力系统集群规划策略【集群划分】
  • 【课堂笔记】隐私计算实训营第四期:“隐语”可信隐私计算开源框架
  • 国外地区经纬度查询免费API接口教程
  • 【深入学习大模型之:微调 GPT 使其自动生成测试用例及自动化用例】
  • Android Compose实现一个文字跑马灯效果控件
  • D76【 python 接口自动化学习】- python 基础之 HTTP
  • 漫步北京小程序构建智慧出行,打造旅游新业态模式
  • box-sizing
  • 了解Redis(第一篇)