在驱动中使用链表
来源:互联网 发布:战舰世界猎户座数据 编辑:程序博客网 时间:2024/06/05 17:10
在驱动程序的开发中经常需要用到链表,常见的链表有单向链表和双向链表,我们只介绍双向链表的使用方法,DDK为我们提供了标准的双向链表 LIST_ENTRY,但这个链表里面没有数据,不能直接使用,我们需要自己定义一个结构体类型,然后将LIST_ENTRY作为结构体的一个子域,如下 所示:
typedef struct _MYDATASTRUCT{
LIST_ENTRY ListEntry;
ULONG number;
} MYDATASTRUCT, *PMYDATASTRUCT;
下面我们就在驱动程序中创建一个链 表,使用刚刚定义的结构体作为节点类型。代码如下所示:
VOID LinkListTest()
{
LIST_ENTRY linkListHead; // 链表
PMYDATASTRUCT pData; // 节点数据
ULONG i = 0; // 计数
//初始化
InitializeListHead(&linkListHead);
// 向链表中插入10个元素
KdPrint(("[ProcessList] Begin insert to link list"));
for (i=0 ; i<10 ; i++)
{ // pData是我们定义的指针,必须被初始化后才能使用
pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool,sizeof(MYDATASTRUCT));
pData->number = i;
// 将其作为一个节点插入链表
InsertHeadList(&linkListHead,&pData->ListEntry);
}
// 从链表中取出所有数据并显示
KdPrint(("[ProcessList] Begin remove from link list\n"));
while(!IsListEmpty(&linkListHead))
{
// 取出一个节点
PLIST_ENTRY pEntry = RemoveTailList(&linkListHead);
// 获取节点内容
pData = CONTAINING_RECORD(pEntry, MYDATASTRUCT, ListEntry);
KdPrint(("%d\n",pData->number));
// 释放节点,ExAllocatePool必须与ExFreePool成对使用
ExFreePool(pData);
}
}
上述代码可以正常地通过编译并运行,但其中存在着一个很大的隐患:它不是多线程安全的。如果有多个线程同时操作同一个链表的话,可能会引发不可预料的后 果,我们可以通过使用自旋锁来避免,修改后的代码如下所示:
VOID LinkListTest()
{
LIST_ENTRY linkListHead; // 链表
PMYDATASTRUCT pData; // 节点数据
ULONG i = 0; // 计数
KSPIN_LOCK spin_lock; // 自旋锁
KIRQL irql; // 中断级别
// 初始化
InitializeListHead(&linkListHead);
KeInitializeSpinLock(&spin_lock);
// 向链表中插入10个元素
KdPrint(("[ProcessList] Begin insert to link list"));
// 锁定,注意这里的irql是个指针
KeAcquireSpinLock(&spin_lock, &irql);
for (i=0 ; i<10 ; i++)
{
pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool,sizeof(MYDATASTRUCT));
pData->number = i;
InsertHeadList(&linkListHead,&pData->ListEntry);
}
// 解锁,注意这里的irql不是指针
KeReleaseSpinLock(&spin_lock, irql);
// 从链表中取出所有数据并显示
KdPrint(("[ProcessList] Begin remove from link list\n"));
// 锁定
KeAcquireSpinLock(&spin_lock, &irql);
while(!IsListEmpty(&linkListHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&linkListHead);
pData = CONTAINING_RECORD(pEntry, MYDATASTRUCT, ListEntry);
KdPrint(("%d\n",pData->number));
ExFreePool(pData);
}
// 解锁
KeReleaseSpinLock(&spin_lock, irql);
}
上述代码介绍了自旋锁的使用方法,但需要注意的是:上面这段代码在实际应用中是没有任何价值的。因为在上述代码我们定义的锁是一个局部变量,被分配在栈 中,这样每个线程在调用该函数的时候,都会重新初始化一个锁,因此这个锁就失去了本来的作用。在实际的编程中,我们应该把锁定义成一个全局变量,或者静态 (static)变量,或者将其创建在堆空间中。
另外,我们还可以为每个链表都定义并初始化一个锁,在需要向该链表插入或移除节点时不使用前面介绍的普通函数,而是使用如下方法:
ExInterlockedInsertHeadList(&linkListHead, &pData->ListEntry, &spin_lock);
pData = (PMYDATASTRUCT)ExInterlockedRemoveHeadList(&linkListHead, &spin_lock);
此时在向链表中插入或移除节点时会自动调用关联的锁进行加锁操作,有效地保证了多线程安全性。
- 在驱动中使用链表
- 如何在VC中使用winpcap驱动
- 如何在VC中使用winpcap驱动
- 驱动中使用内核链表
- 如何在Jbuilder9中使用SQLServer JDBC驱动
- 如何在Jbuilder9中使用SQLServer JDBC驱动
- 在RFT中使用Excel进行数据驱动测试
- Android PMEM驱动研究 在应用程序中使用PMEM
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用官方驱动操作MongoDB
- 如何在JDBC中使用.properties文件配置驱动
- MongoDB在.NET中使用官方驱动的插入操作
- 在C#中使用官方驱动操作MongoDB
- 在C#中使用samus驱动操作MongoDB
- adb工具编译错误解决。
- C++关联容器
- 在IE8,FF中<select>控件文字垂直居中的处理方法
- 发现个Mybatis的bug: XML fragments parsed from previous mappers does not contain value for
- JQuery对iframe页面的操作
- 在驱动中使用链表
- Dlink跨数据库查询
- Android各种蓝牙设备的UUID
- 2014年1月20日 民营银行来了
- ubuntu下Dia绘图软件无法输入中文的解决办法。
- Android 入门 - 模拟器加速
- 简单的Android服务端和客户端登录交互(客户端)
- svn服务配置和日常维护命令
- Maven的工程依赖和JAR包依赖