Widows下自旋锁的实现

本文探讨了Windows NT操作系统中SpinLock的实现机制,并详细解释了通过调整IRQL(Interrupt Request Level)来实现同步和互斥的过程。文章对比了原子指令实现和其他常见方法,强调了在不同IRQL级别下使用特定SpinLock例程的重要性。
In this part, we’ll discuss how the OS realize SpinLocks via IRQL

Realization of SpinLocks:

Spin locks are very commonly used in drivers to protect data that will be accessed by multiple driver routines running at varying IRQLs. But what’s it’s realizaton ?
Every book about “Operating System?will tell us that an atomic test-and-set instruction will be adopted. Is windows os uses this way ? The answer is NO. What windows nt adopts is IRQL. That is the spinlock routines will change the IRQL.

There are some kernel routines to acquire/release SpinLocks available for driver developers. These routines are not strange faces, so I’ll not introduce their functionalities here.

VOID
KeAcquireSpinLock(
IN PKSPIN_LOCK SpinLock,
OUT PKIRQL OldIrql
);

VOID
KeReleaseSpinLock(
IN PKSPIN_LOCK SpinLock,
IN KIRQL NewIrql
);

VOID
KeAcquireSpinLockAtDpcLevel(
IN PKSPIN_LOCK SpinLock
);

VOID
KeReleaseSpinLockFromDpcLevel(
IN PKSPIN_LOCK SpinLock
);

DDk says that “Callers of KeAcquireSpinLock must be running at IRQL <= DISPATCH_LEVEL? for dispatch_level routines, .it would be better to use KeAcuireSpinLockAtDpcLevel, and that callers of KeReleaseSpinLock are running at IRQL DISPATCH_LEVEL, but why ?

The following codes tell us the answer:

kd> u Hal!KeAcquireSpinLock
hal!KeAcquireSpinLock:
80066806 8b4c2404 mov ecx,[esp+0x4]
8006680a e849c7ffff call hal!KfAcquireSpinLock (80062f58)
8006680f 8b4c2408 mov ecx,[esp+0x8]
80066813 8801 mov [ecx],al
80066815 c20800 ret 0x8

hal!KfAcquireSpinLock:
80062f58 33c0 xor eax,eax

// Save current IRQL to al
80062f5a a024f0dfff mov al, [ffdff024]

// Change Current IRQL to Dispatch Level
80062f5f c60524f0dfff02 mov byte ptr [ffdff024],0x2
80062f66 c3 ret

Then we get the result: The acquiration of spin lock is just only improve current IRQL to DISPATCH_LEVEL. So the article “A Catalog of NT Synchronization Mechanisms?(refer. 2) says “Always relying on spin locks to protect access to shared data may be overkill? Because after the SpinLock is acquired , the current IRQL will be DISPATCH_LEVEL and then the NT dispatcher (scheduler) preemption will be disabled.

But for the routine which is already running at DISPATCH_LEVEL, they are advised .to use KeAcquireSpinLockAtDpcLevel instead. We can image what KeAcquireSpinLockAtDpcLevel do?

kd> u KeAcquireSpinLockAtDpcLevel
nt!KeAcquireSpinLockAtDpcLevel:
804022e4 c20400 ret 0x4

nt!KeReleaseSpinLockFromDpcLevel:
804022f4 c20400 ret 0x4

These two routines do nothing, and just return. As all DISPATCH_LEVEL all the routines will be executed synchronously, they can not interrupt each other, i.e. they are alreary synchronized.

When current IRQL > DISPATCH_LEVEL, we are warned never to call spin lock routines , or we’ll get BSOD. Here we get the reason: KeAcquireSpinLock will try to lower the current IRQL, which is not permitted by NT.
### Windows系统中自旋锁实现原理与机制 在Windows操作系统中,自旋锁是一种轻量级的同步原语,主要用于保护共享资源的互斥访问。与传统的互斥锁不同,自旋锁在发生竞争时不会将线程挂起,而是让线程以“原地等待”的方式不断检查锁的状态,直到成功获取锁为止[^1]。 #### 自旋锁的工作原理 自旋锁的核心思想是通过原子操作来确保线程间的同步。当一个线程尝试获取自旋锁时,如果锁已经被其他线程占用,则该线程会进入一个循环(即“自旋”),持续检查锁的状态,直到锁被释放并成功获取[^2]。这种机制适用于锁持有时间较短的场景,因为长时间的自旋会导致CPU资源浪费。 在Windows内核中,自旋锁通常用于驱动程序的同步处理。初始化时,自旋锁处于解锁状态,任何线程都可以成功“获取”锁。一旦某个线程获取了锁,自旋锁便进入锁定状态,其他试图获取锁的线程将进入自旋状态,直到锁被释放[^3]。 #### 自旋锁实现细节 在Windows内核中,自旋锁实现依赖于原子操作和硬件支持。以下是一个简化的伪代码示例,展示了自旋锁的基本实现逻辑: ```c typedef struct _SPIN_LOCK { volatile LONG Lock; // 用于表示锁状态的变量 } SPIN_LOCK, *PSPIN_LOCK; // 初始化自旋锁 void InitializeSpinLock(PSPIN_LOCK spinLock) { spinLock->Lock = 0; // 初始状态为解锁 } // 尝试获取自旋锁 void AcquireSpinLock(PSPIN_LOCK spinLock) { while (InterlockedExchange(&spinLock->Lock, 1) != 0) { // 如果锁已被占用,则继续自旋 YieldProcessor(); // 可选:减少CPU占用 } } // 释放自旋锁 void ReleaseSpinLock(PSPIN_LOCK spinLock) { InterlockedExchange(&spinLock->Lock, 0); // 将锁状态重置为解锁 } ``` 上述代码中,`InterlockedExchange` 是一种原子操作函数,用于确保多线程环境下的同步。当线程调用 `AcquireSpinLock` 函数时,如果锁已被占用,则线程会进入一个循环,持续检查锁的状态,直到成功获取锁[^4]。 #### 自旋锁的优点与局限性 - **优点**:自旋锁避免了线程切换的开销,适合锁持有时间较短的场景。 - **局限性**:如果锁的持有时间过长,自旋锁会导致CPU资源浪费,因此不适合保护长时间运行的临界区。 ### 相关问题
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值