自旋锁
自旋锁
自旋锁是内核中提供的一种高IRQL锁,用同步以及独占的方式访问某个资源。
KSPIN_LOCK my_spin_lock; |
自旋锁的使用方法:
KIRQL irql; //KIRQL是一个中断级 |
KeAcquireSpinLock 和 KeReleaseSpinLock 之间的代码是只有单线程执行的,其他的线程会停留在 KeAcquireSpinLock 等候,直到 KeReleaseSpinLock 被调用。换句话说,只有一个线程能够获得自旋锁。
注意: 锁一般不会定义成局部变量,可以使用静态变量、全局变量,或者分配在池(POOL)中。因为每个线程来执行的时候都会重新初始化一个锁。只有所有的线程共用一个锁,锁才有意义。
/*正确使用自旋锁的例子*/ |
双向链表自旋锁
在双向链表中使用自旋锁的目的是保证多线程安全。在操作链表之前,调用KeAcquireSpinLock 来获取锁,在操作完成之后,调用 KeReleaseSpinLock 来释放锁。
链表中初始化自旋锁。LIST_ENTRY有一系列操作,这些操作并不需要使用者自己调用获取与释放锁,只需要为每个链表定义并初始化一个锁即可。
typedef struct _FILE_INFO |
正常情况下链表插入一个节点:
FILE_INFO my_file_infor={0}; |
加锁的情况下链表插入一个节点:
ExInterlockInsertHeadList( |
加锁的情况下链表移除一个节点:
PLSIT_ENTRY pRemoveEntry = NULL; |
注意: 锁一般不会定义成局部变量。可以使用静态变量、全局变量,或者分配在堆中。
队列自旋锁
队列自旋锁遵守“谁先等待,谁先获取自旋锁”的原则。其过程和队列的“First inFirst out”特点非常类似,正是由于这个原因,这种自旋锁被称为“队列自旋锁”。
队列自旋锁的获取和释放
VOID KeAcquireInStackQueueSpinlock( |
队列自旋锁初始化
KSPIN_LOCK my_Queue_SpinLock = {0}; |
队列自旋锁的获取和释放
KLOCK_QUEUE_HANDLE my_lock_queue_handle; |
注意:
- 队列自旋锁的使用增加了一个 KLOCK_QUEUE_HANDLE 数据结构,这个数据结构唯一地表示一个队列自旋锁。
- 普通自旋锁和队列自旋锁虽然都是使用 KeInitializeSpinLock 函数来初始化的,但是对于一个初始化后的自旋锁,要么按普通自旋锁方式来使用,要么按队列自旋锁方式来使用,绝对不能混用。