在驅動中使用鍊錶

2021-08-25 03:10:38 字數 1415 閱讀 8506

原始出處:

在驅動程式的開發中經常需要用到鍊錶,常見的鍊錶有單向鍊錶和雙向鍊錶,我們只介紹雙向鍊錶的使用方法,ddk為我們提供了標準的雙向鍊錶 list_entry,但這個鍊錶裡面沒有資料,不能直接使用,我們需要自己定義乙個結構體型別,然後將list_entry作為結構體的乙個子域,如下 所示:

typedef struct _mydatastruct mydatastruct, *pmydatastruct;

實際上把list_entry放在結構體的第乙個子域才是較好的做法,此處我們不過多地關心,反正用法都是大同小異。下面我們就在驅動程式中建立乙個鏈 表,使用剛剛定義的結構體作為節點型別。**如下所示:

void  linklisttest()

// 從鍊錶中取出所有資料並顯示

kdprint(("[processlist] begin remove from link list\n"));

while(!islistempty(&linklisthead))}

上述**可以正常地通過編譯並執行,但其中存在著乙個很大的隱患:它不是多執行緒安全的。如果有多個執行緒同時操作同乙個鍊錶的話,可能會引發不可預料的後 果,我們可以通過使用自旋鎖來避免,修改後的**如下所示:

void  linklisttest()

// 解鎖,注意這裡的irql不是指標

kereleasespinlock(&spin_lock, irql);

// 從鍊錶中取出所有資料並顯示

kdprint(("[processlist] begin remove from link list\n"));

// 鎖定

keacquirespinlock(&spin_lock, &irql);

while(!islistempty(&linklisthead))

// 解鎖

kereleasespinlock(&spin_lock, irql);}

上述**介紹了自旋鎖的使用方法,但需要注意的是:上面這段**在實際應用中是沒有任何價值的。因為在上述**我們定義的鎖是乙個區域性變數,被分配在棧 中,這樣每個執行緒在呼叫該函式的時候,都會重新初始化乙個鎖,因此這個鎖就失去了本來的作用。在實際的程式設計中,我們應該把鎖定義成乙個全域性變數,或者靜態 (static)變數,或者將其建立在堆空間中。

另外,我們還可以為每個鍊錶都定義並初始化乙個鎖,在需要向該鍊錶插入或移除節點時不使用前面介紹的普通函式,而是使用如下方法:

exinterlockedinsertheadlist(&linklisthead, &pdata->listentry, &spin_lock);

pdata = (pmydatastruct)exinterlockedremoveheadlist(&linklisthead, &spin_lock);

此時在向鍊錶中插入或移除節點時會自動呼叫關聯的鎖進行加鎖操作,有效地保證了多執行緒安全性。

在鍊錶中使用頭結點與尾指標

1 頭結點 首先,不要被以下三個片語弄混了 煉表頭 資料內容為第乙個元素的結點。頭指標 指向頭結點元素的指標。頭結點 資料內容無效,其指標是頭指標。一句話描述為 頭指標是指向頭結點的指標,頭結點是指向煉表頭的結點。對於乙個鍊錶來說,頭指標是一定存在的,是訪問鍊錶的入口,如果沒有頭指標則無法對其進行訪...

驅動中煉表的使用

ddk中定義了list entry雙向鍊錶結構,這樣把資料和鍊錶分開的定義方法,降低了耦合度。typedef struct list entry mydatastruct,pmydatastruct 鍊錶的初始化 initializelisthead plist entry plisthead 引數...

在中使用SQLDMO

曾幾何時,夥伴們為的公升級傷透了腦筋.往往程式的公升級趕不上資料庫的公升級 版本控制的好,這也許不是什麼問題,但對於很大一部分中國公司來說這是無法避免的 而有些n久以前的資料庫要使用新程式的時候,資料庫的公升級簡直就是無從下手.所以對比資料庫公升級的緊要性就逐漸的凸現出來.對於表和字段的公升級按道理...