详解C语言内核中的自旋锁结构
短信预约 -IT技能 免费直播动态提醒
提到自旋锁那就必须要说链表,在上一篇《驱动开发:内核中的链表与结构体》文章中简单实用链表结构来存储进程信息列表,相信读者应该已经理解了内核链表的基本使用,本篇文章将讲解自旋锁的简单应用,自旋锁是为了解决内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高IRQL锁,用同步以及独占的方式访问某个资源。
首先以简单的链表为案例,链表主要分为单向链表与双向链表,单向链表的链表节点中只有一个链表指针,其指向后一个链表元素,而双向链表节点中有两个链表节点指针,其中Blink
指向前一个链表节点Flink
指向后一个节点,以双向链表为例。
#include <ntifs.h>
#include <ntstrsafe.h>
typedef struct _MyStruct
{
ULONG x;
ULONG y;
LIST_ENTRY lpListEntry;
}MyStruct,*pMyStruct;
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动卸载成功 \n");
}
// By: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("By:LyShark \n");
DbgPrint("Email:me@lyshark.com \n");
// 初始化头节点
LIST_ENTRY ListHeader = { 0 };
InitializeListHead(&ListHeader);
// 定义链表元素
MyStruct testA = { 0 };
MyStruct testB = { 0 };
MyStruct testC = { 0 };
testA.x = 100;
testA.y = 200;
testB.x = 1000;
testB.y = 2000;
testC.x = 10000;
testC.y = 20000;
// 分别插入节点到头部和尾部
InsertHeadList(&ListHeader, &testA.lpListEntry);
InsertTailList(&ListHeader, &testB.lpListEntry);
InsertTailList(&ListHeader, &testC.lpListEntry);
// 节点不为空 则 移除一个节点
if (IsListEmpty(&ListHeader) == FALSE)
{
RemoveEntryList(&testA.lpListEntry);
}
// 输出链表数据
PLIST_ENTRY pListEntry = NULL;
pListEntry = ListHeader.Flink;
while (pListEntry != &ListHeader)
{
// 计算出成员距离结构体顶部内存距离
pMyStruct ptr = CONTAINING_RECORD(pListEntry, MyStruct, lpListEntry);
DbgPrint("节点元素X = %d 节点元素Y = %d \n", ptr->x, ptr->y);
// 得到下一个元素地址
pListEntry = pListEntry->Flink;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
链表输出效果如下:
如上所述,内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高IRQL锁,用同步以及独占的方式访问某个资源。
#include <ntifs.h>
#include <ntstrsafe.h>
typedef struct _MyStruct
{
ULONG x;
ULONG y;
LIST_ENTRY lpListEntry;
}MyStruct, *pMyStruct;
// 定义全局链表和全局锁
LIST_ENTRY my_list_header;
KSPIN_LOCK my_list_lock;
// 初始化
void Init()
{
InitializeListHead(&my_list_header);
KeInitializeSpinLock(&my_list_lock);
}
// 函数内使用锁
void function_ins()
{
KIRQL Irql;
// 加锁
KeAcquireSpinLock(&my_list_lock, &Irql);
DbgPrint("锁内部执行 \n");
// 释放锁
KeReleaseSpinLock(&my_list_lock, Irql);
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动卸载成功 \n");
}
// By: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("By:LyShark \n");
DbgPrint("Email:me@lyshark.com \n");
// 初始化链表
Init();
// 分配链表空间
pMyStruct testA = (pMyStruct)ExAllocatePool(NonPagedPoolExecute, sizeof(pMyStruct));
pMyStruct testB = (pMyStruct)ExAllocatePool(NonPagedPoolExecute, sizeof(pMyStruct));
// 赋值
testA->x = 100;
testA->y = 200;
testB->x = 1000;
testB->y = 2000;
// 向全局链表中插入数据
if (NULL != testA && NULL != testB)
{
ExInterlockedInsertHeadList(&my_list_header, (PLIST_ENTRY)&testA->lpListEntry, &my_list_lock);
ExInterlockedInsertTailList(&my_list_header, (PLIST_ENTRY)&testB->lpListEntry, &my_list_lock);
}
function_ins();
// 移除节点A并放入到remove_entry中
PLIST_ENTRY remove_entry = ExInterlockedRemoveHeadList(&testA->lpListEntry, &my_list_lock);
// 输出链表数据
while (remove_entry != &my_list_header)
{
// 计算出成员距离结构体顶部内存距离
pMyStruct ptr = CONTAINING_RECORD(remove_entry, MyStruct, lpListEntry);
DbgPrint("节点元素X = %d 节点元素Y = %d \n", ptr->x, ptr->y);
// 得到下一个元素地址
remove_entry = remove_entry->Flink;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
加锁后执行效果如下:
到此这篇关于详解C语言内核中的自旋锁结构的文章就介绍到这了,更多相关C语言内核 自旋锁内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341