詳解C語言內(nèi)核中的自旋鎖結(jié)構(gòu)
提到自旋鎖那就必須要說鏈表,在上一篇《驅(qū)動開發(fā):內(nèi)核中的鏈表與結(jié)構(gòu)體》文章中簡單實(shí)用鏈表結(jié)構(gòu)來存儲進(jìn)程信息列表,相信讀者應(yīng)該已經(jīng)理解了內(nèi)核鏈表的基本使用,本篇文章將講解自旋鎖的簡單應(yīng)用,自旋鎖是為了解決內(nèi)核鏈表讀寫時(shí)存在線程同步問題,解決多線程同步問題必須要用鎖,通常使用自旋鎖,自旋鎖是內(nèi)核中提供的一種高IRQL鎖,用同步以及獨(dú)占的方式訪問某個(gè)資源。
首先以簡單的鏈表為案例,鏈表主要分為單向鏈表與雙向鏈表,單向鏈表的鏈表節(jié)點(diǎn)中只有一個(gè)鏈表指針,其指向后一個(gè)鏈表元素,而雙向鏈表節(jié)點(diǎn)中有兩個(gè)鏈表節(jié)點(diǎn)指針,其中Blink指向前一個(gè)鏈表節(jié)點(diǎn)Flink指向后一個(gè)節(jié)點(diǎn),以雙向鏈表為例。
#include <ntifs.h>
#include <ntstrsafe.h>
/*
// 鏈表節(jié)點(diǎn)指針
typedef struct _LIST_ENTRY
{
struct _LIST_ENTRY *Flink; // 當(dāng)前節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)
struct _LIST_ENTRY *Blink; // 當(dāng)前節(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
}LIST_ENTRY, *PLIST_ENTRY;
*/
typedef struct _MyStruct
{
ULONG x;
ULONG y;
LIST_ENTRY lpListEntry;
}MyStruct,*pMyStruct;
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驅(qū)動卸載成功 \n");
}
// By: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("By:LyShark \n");
DbgPrint("Email:me@lyshark.com \n");
// 初始化頭節(jié)點(diǎ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;
// 分別插入節(jié)點(diǎn)到頭部和尾部
InsertHeadList(&ListHeader, &testA.lpListEntry);
InsertTailList(&ListHeader, &testB.lpListEntry);
InsertTailList(&ListHeader, &testC.lpListEntry);
// 節(jié)點(diǎn)不為空 則 移除一個(gè)節(jié)點(diǎn)
if (IsListEmpty(&ListHeader) == FALSE)
{
RemoveEntryList(&testA.lpListEntry);
}
// 輸出鏈表數(shù)據(jù)
PLIST_ENTRY pListEntry = NULL;
pListEntry = ListHeader.Flink;
while (pListEntry != &ListHeader)
{
// 計(jì)算出成員距離結(jié)構(gòu)體頂部內(nèi)存距離
pMyStruct ptr = CONTAINING_RECORD(pListEntry, MyStruct, lpListEntry);
DbgPrint("節(jié)點(diǎn)元素X = %d 節(jié)點(diǎn)元素Y = %d \n", ptr->x, ptr->y);
// 得到下一個(gè)元素地址
pListEntry = pListEntry->Flink;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
鏈表輸出效果如下:

如上所述,內(nèi)核鏈表讀寫時(shí)存在線程同步問題,解決多線程同步問題必須要用鎖,通常使用自旋鎖,自旋鎖是內(nèi)核中提供的一種高IRQL鎖,用同步以及獨(dú)占的方式訪問某個(gè)資源。
#include <ntifs.h>
#include <ntstrsafe.h>
/*
// 鏈表節(jié)點(diǎn)指針
typedef struct _LIST_ENTRY
{
struct _LIST_ENTRY *Flink; // 當(dāng)前節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)
struct _LIST_ENTRY *Blink; // 當(dāng)前節(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
}LIST_ENTRY, *PLIST_ENTRY;
*/
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);
}
// 函數(shù)內(nèi)使用鎖
void function_ins()
{
KIRQL Irql;
// 加鎖
KeAcquireSpinLock(&my_list_lock, &Irql);
DbgPrint("鎖內(nèi)部執(zhí)行 \n");
// 釋放鎖
KeReleaseSpinLock(&my_list_lock, Irql);
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驅(qū)動卸載成功 \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;
// 向全局鏈表中插入數(shù)據(jù)
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();
// 移除節(jié)點(diǎn)A并放入到remove_entry中
PLIST_ENTRY remove_entry = ExInterlockedRemoveHeadList(&testA->lpListEntry, &my_list_lock);
// 輸出鏈表數(shù)據(jù)
while (remove_entry != &my_list_header)
{
// 計(jì)算出成員距離結(jié)構(gòu)體頂部內(nèi)存距離
pMyStruct ptr = CONTAINING_RECORD(remove_entry, MyStruct, lpListEntry);
DbgPrint("節(jié)點(diǎn)元素X = %d 節(jié)點(diǎn)元素Y = %d \n", ptr->x, ptr->y);
// 得到下一個(gè)元素地址
remove_entry = remove_entry->Flink;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
加鎖后執(zhí)行效果如下:

到此這篇關(guān)于詳解C語言內(nèi)核中的自旋鎖結(jié)構(gòu)的文章就介紹到這了,更多相關(guān)C語言內(nèi)核 自旋鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言關(guān)鍵字之a(chǎn)uto register詳解
這篇文章主要為大家介紹了C語言關(guān)鍵字之a(chǎn)uto register,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01
詳解C++的靜態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配
內(nèi)存分配 (Memory Allocation) 是指為計(jì)算機(jī)程序或服務(wù)分配物理內(nèi)存空間或虛擬內(nèi)存空間的一個(gè)過程,本文主要介紹了C++的靜態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配,感興趣的同學(xué)可以參考閱讀2023-06-06
C/C++ 開發(fā)神器CLion使用入門超詳細(xì)教程
這篇文章主要介紹了C/C++ 開發(fā)神器CLion使用入門超詳細(xì)教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Matlab實(shí)現(xiàn)三維投影繪制的示例代碼
這篇文章系小編為大家?guī)砹艘粋€(gè)三維投影繪制函數(shù)(三視圖繪制),函數(shù)支持三維曲線、曲面、三維多邊形、參數(shù)方程曲線、參數(shù)方程曲面的投影繪制,需要的可以參考一下2022-08-08

