Windows驱动
+ -

自旋锁KSPIN_LOCK

2021-07-01 454 1

链表之类的结构总是涉及到恼人的多线程同步问题,这时候就必须使用锁。这里只介绍最简单的自选锁。

有些读者可能疑惑锁存在的意义。这和多线程操作有关。在驱动开发的代码中,大多是存在于多线程执行环境的。就是说可能有几个线程在同时调用当前函数。

这样一来,前文中提及的追加链表节点函数就根本无法使用了。因为MyFileInforAppendNode这个函数只是简单的操作链表。如果两个线程同时调用这个函数来操作链表的话:注意这个函数操作的是一个全局变量链表。换句话说,无论有多少个线程同时执行,他们操作的都是同一个链表。这就可能发生,一个线程插入一个节点的同时,另一个线程也同时插入。他们都插入同一个链表节点的后边。这时链表就会发生问题。到底最后插入的是哪一个呢?要么一个丢失了。要么链表被损坏了。

如下的代码初始化获取一个自选锁:

KSPIN_LOCK my_spin_lock;
KeInitializeSpinLock(&my_spin_lock);

KeInitializeSpinLock这个函数没有返回值。下面的代码展示了如何使用这个SpinLock。在KeAcquireSpinLock和KeReleaseSpinLock之间的代码是只有单线程执行的。其他的线程会停留在KeAcquireSpinLock等候。直到KeReleaseSpinLock被调用。KIRQL是一个中断级。KeAcquireSpinLock会提高当前的中断级。但是目前忽略这个问题。中断级在后面讲述。

KIRQL irql;
KeAcquireSpinLock(&my_spin_lock,&irql);
// To do something …
KeReleaseSpinLock(&my_spin_lock,irql);

初学者要注意的是,像下面写的这样的“加锁”代码是没有意义的,等于没加锁:

void MySafeFunction()
{
    KSPIN_LOCK my_spin_lock;
    KIRQL irql;
    KeInitializeSpinLock(&my_spin_lock);
    KeAcquireSpinLock(&my_spin_lock,&irql);
    // 在这里做要做的事情…
    KeReleaseSpinLock(&my_spin_lock,irql);
}

原因是my_spin_lock在堆栈中。每个线程来执行的时候都会重新初始化一个锁。只有所有的线程共用一个锁,锁才有意义。所以,锁一般不会定义成局部变量。可以使用静态变量、全局变量,或者分配在堆中(见前面的2.2.1内存的分配与释放一节)。请读者自己写出正确的方法。

LIST_ENTRY有一系列的操作。这些操作并不需要使用者自己调用获取与释放锁。只需要为每个链表定义并初始化一个锁即可:

LIST_ENTRY        my_list_head;        // 链表头
KSPIN_LOCK    my_list_lock;        // 链表的锁

// 链表初始化函数
void MyFileInforInilt()
{
    InitializeListHead(&my_list_head);
    KeInitializeSpinLock(&my_list_lock);
}

链表一旦完成了初始化,之后的可以采用一系列加锁的操作来代替普通的操作。比如插入一个节点,普通的操作代码如下:

InsertHeadList(&my_list_head, (PLIST_ENTRY)& my_file_infor);

换成加锁的操作方式如下:

ExInterlockedInsertHeadList(
    &my_list_head, 
    (PLIST_ENTRY)& my_file_infor,
    &my_list_lock);

注意不同之处在于,增加了一个KSPIN_LOCK的指针作为参数。在ExInterlockedInsertHeadList中,会自动的使用这个KSPIN_LOCK进行加锁。类似的还有一个加锁的Remove函数,用来移除一个节点,调用如下:

    my_file_infor = ExInterlockedRemoveHeadList (
        &my_list_head, 
        &my_list_lock);

这个函数从链表中移除第一个节点。并返回到my_file_infor中。

0 篇笔记 写笔记

自旋锁KSPIN_LOCK
链表之类的结构总是涉及到恼人的多线程同步问题,这时候就必须使用锁。这里只介绍最简单的自选锁。有些读者可能疑惑锁存在的意义。这和多线程操作有关。在驱动开发的代码中,大多是存在于多线程执行环境的。就是说可能有几个线程在同时调用当前函数。这样一来,前文中提及的追加链表节点函数就根本无法使用了。因为My......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!