linux hlist,linux內核V2.6.11學習筆記(2)--list和hlist

這兩個數據結構在內核中隨處可見,不得不拿出來單獨講講.

這兩個數據結構都是為了方便內核開發者在使用到類似數據結構的時候不必自行開發(雖然不難),因此它們需要做到足夠的"通用性",也就是說,今天可以用它們做一個存放進程的鏈表,明天同樣可以做一個封裝定時器的鏈表.兩個數據結構的對外API封裝了針對它們的基本操作,也是最常見的操作,比如遍歷,查找等等.

一般的,如果我們需要寫一個鏈表,會這么寫:

structnode

{structnode*next;

data_t?data;

}

其中的data假設是鏈表中元素存放的數據.然后針對這個鏈表寫一些相關操作的API.

假設下一個需求,鏈表存放的元素變了,那么我們還需要定義一個新的數據結構,寫一些相關操作的API.

但是,其實我們需要做的事情都是類似:遍歷一個鏈表,按照某個條件定位到其中的一個元素,等等.有沒有辦法將操作比較特定數據的操作交給使用者,而封裝出一套滿足基本鏈表操作的API呢?

C++里面的做法是STL,使用的是范型技術,在運行時才直到容器所要存放的數據元素的類型.而通過C++中的重載,函數對象等技術可以平滑的實現操作不同數據元素.

C中沒有這些技術,用STL的方式恐怕是走不通了.

于是,內核采用了另一種方法解決這個問題.

內核中實現的鏈表數據結構是這樣的:

structlist_head?{structlist_head*next,*prev;

};

可見,這個鏈表中只有分別指向前一個和后一個元素的指針,而沒有特定的類型.也就是說,這個數據類型關注的僅僅是鏈表本身的東西,與具體的數據無關.

當需要使用鏈表的時候,可以這樣來:

structnode

{structlist_head?link;

data_t?data;

}

那么,如何根據這個link定位到所需要管理的數據呢?

內核中定義了這么一個宏:

#definecontainer_of(ptr,?type,?member)?\((type*)((char*)(ptr)-(unsignedlong)(&((type*)0)->member)))

這個宏的作用是容器類型type中有一個名為member的list_head元素,要根據這個元素的指針(ptr)得到存放它的type類型的對象的地址.

一步一步看這個宏:

1) &((type*)0)->member)

從C的角度出發, 假設結構體node中有一個成員data, 那么對于一個指向結構體node的指針p來說,p->data與p的地址相差為data這個域在結構體node中的偏移量.

于是,&(p->member)就是type類型的指針p中的成員member的地址,而這個地址是p的地址+member成員在這個結構體中的偏移,

當這個p變成了0之后,自然就得出了member成員在結構體type中的偏移量.

所以,&((type*)0)->member)獲得了結構體type中成員member的偏移量.

2) (char*)(ptr)-(unsignedlong)(&((type*)0)->member))

這里ptr是list_head的指針,也就是member成員的指針,因此兩者相減得到了存放member的type結構體的指針.

3)((type*)((char*)(ptr)-(unsignedlong)(&((type*)0)->member)))

最后在前面加上一個類型轉換,將前面得到的指針轉換成type類型.

這就是內核中根據list_head指針得到容納它的容器地址的魔法.

理解了這個,理解內核中的鏈表操作也就不再難.

接著看hlist,首先看看內核中的定義:

struct hlist_head {

struct hlist_node *first;

};

struct hlist_node {

struct hlist_node *next, **pprev;

};

這個數據結構與一般的hash-list數據結構定義有以下的區別:

1) 首先,hash的頭節點僅存放一個指針,也就是first指針,指向的是list的頭結點,沒有tail指針也就是指向list尾節點的指針,這樣的考慮是為了節省空間--尤其在hash bucket很大的情況下可以節省一半的指針空間.

2) list的節點有兩個指針,但是需要注意的是pprev是指針的指針,它指向的是前一個節點的next指針(見下圖).

現在疑問來了:為什么pprev不是prev也就是一個指針,用于簡單的指向list的前一個指針呢?這樣即使對于first而言,它可以將prev指針指向list的尾結點.

主要是基于以下幾個考慮:

1) hash-list中的list一般元素不多(如果太多了一般是設計出現了問題),即使遍歷也不需要太大的代價,同時需要得到尾結點的需求也不多.

2) 如果對于一般節點而言,prev指向的是前一個指針,而對于first也就是hash的第一個元素而言prev指向的是list的尾結點,那么在刪除一個元素的時候還需要判斷該節點是不是first節點進行處理.而在hlist提供的刪除節點的API中,并沒有帶上hlist_head這個參數,因此做這個判斷存在難度.3) 以上兩點說明了為什么不使用prev,現在來說明為什么需要的是pprev,也就是一個指向指針的指針來保存前一個節點的next指針--因為這樣做即使在刪除的節點是first節點時也可以通過*pprev = next;直接修改指針的指向.來看刪除一個節點和修改list頭結點的兩個API:

staticinlinevoidhlist_add_head(structhlist_node*n,structhlist_head*h)

{structhlist_node*first=h->first;

n->next=first;if(first)

first->pprev=&n->next;

h->first=n;

n->pprev=&h->first;//此時n是hash的first指針,因此它的pprev指向的是hash的first指針的地址}staticinlinevoid__hlist_del(structhlist_node*n)

{structhlist_node*next=n->next;structhlist_node**pprev=n->pprev;*pprev=next;//pprev指向的是前一個節點的next指針,而當該節點是first節點時指向自己,因此兩種情況下不論該節點是一般的節點還是頭結點都可以通過這個操作刪除掉所需刪除的節點if(next)

next->pprev=pprev;

}

8a38410ca05eb0e52ab322dbd927d922.png

參考資料:

1)http://blog.chinaunix.net/u/12592/showart.php?id=451619

我對里面的示意圖做了一下修改,主要是將list頭結點的pprev指針指向hash的first指針地址.這樣看上去更明白一些.

2)http://linux.chinaunix.net/bbs/viewthread.php?tid=1032772

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395433.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395433.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395433.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

14-angular.isDefined

判斷括號內的值是否存在。 格式: angular.isDefined(value); value: 被判斷是否存在的值。 返回值: true/false轉載于:https://www.cnblogs.com/ms-grf/p/6978886.html

實施工程師1分鐘即時演講_我是如何在1年內從時裝模特轉變為軟件工程師的

實施工程師1分鐘即時演講In 2015 I knew almost nothing about coding. Today, I’m a software engineer and a teacher at a code school for kids.在2015年,我對編碼幾乎一無所知。 今天,我是一名軟件工程師,還是一所代碼學校的兒童老師。…

MSSQL分組取后每一組的最新一條記錄

數據庫中二張表,用戶表和獎金記錄表,獎金記錄表中一個用戶有多條信息,有一個生效時間,現在要查詢: 獎金生效時間在三天前,每個用戶取最新一條獎金記錄,且用戶末鎖定 以前用的方法是直接寫在C#代…

android模擬器插件,Android模擬器插件找不到android SDK

首先,克隆項目詹金斯一直輸出后:[android] No Android SDK found; lets install it automatically...[android] Going to install required Android SDK components...[android] Installing the platform-tool,tool SDK component(s)...$ /var/lib/jenki…

讀書筆記--模板與泛型編程

了解隱式接口和編譯期多態 編譯期多態和運行期多態 運行期多態就好比是virtual函數再運行的時候才確定該virtual函數該被綁定為哪個函數,運行的時候才確定函數類型。  編譯期多態就好比是泛型編程和模板編程中,在編譯的時候才確定哪個函數該被調用&…

棧和遞歸的關系 144:Binary Tree Preorder Traversal

前序遍歷:根左右 //用棧來實現非遞歸解法/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:vec…

運行級別

ls -l /usr/lib/system/runlevel*target (查看運行級別)Linux系統有7個運行級別(runlevel)運行級別0:系統停機狀態,系統默認運行級別不能設為0,否則不能正常啟動運行級別1:單用戶工作狀態,roo…

微信sdk swift版_使用Swift 4的iOS版Google Maps SDK終極指南

微信sdk swift版by Dejan Atanasov通過Dejan Atanasov 使用Swift 4的iOS版Google Maps SDK終極指南 (Your ultimate guide to the Google Maps SDK on iOS, using Swift 4) Many iOS apps use Google Maps. This is a very common feature, so I have decided to prepare an u…

精確覆蓋DLX算法模板

代碼 struct DLX {int n,id;int L[maxn],R[maxn],U[maxn],D[maxn];int C[maxn],S[maxn],loc[maxn][2];void init(int nn0) //傳列長{nnn;for(int i0;i<n;i) U[i]D[i]i,L[i]i-1,R[i]i1;L[0]n; R[n]0;idn;memset(S,0,sizeof(S));}void AddRow(int x,int col,int A[]) //傳入參…

android 代碼布局設置wrap_content,android ScrollView布局(wrap_content,最大大小)

我最后編寫了自己的類,擴展了ScrollView既然你問……這是代碼.可能不是最干凈但它做我想要的.請注意,它期望在創建視圖時設置layout_weight,并且不應在父LinearLayout中設置weigthSum,否則你會得到有趣的東西(因為這個的權重從原始值變為0,具體取決于大小ScrollView的內容)首先…

ABAP數據類型

數據類型表&#xff1a; 類型縮寫 類型 默認長度 允許長度 初始值 描述 C 文本型 1 Space 字符串數據,如Program D 日期型 8 8 00000000 日期數據,格式為YYYYMMDD F 浮點型 8 8 0 浮點數 I 整型 4 10 0 帶正負符號的整數 N 數值型 1 31 00……

cocos2d-x C++ 原始工程引擎運行機制解析

新建一個工程&#xff0c;相信感興趣的同學都想知道cocos引擎都是如何運行的 想知道是如何運行的&#xff0c;看懂四個文件即可 話不多說&#xff0c;上代碼&#xff1a; 1、首先解釋 AppDelegate.h 1 #ifndef _APP_DELEGATE_H_2 #define _APP_DELEGATE_H_3 4 #include "…

web高德maker動畫_Web Maker —我如何構建一個快速的離線前端游樂場

web高德maker動畫by kushagra gour由kushagra gour Web Maker —我如何構建一個快速的離線前端游樂場 (Web Maker — How I built a fast, offline front-end playground) Web Maker is a Chrome extension that gives you a blazing fast and offline front-end playground —…

時間小知識對于時間轉換可能有幫助

那么UTC與世界各地的時間應如何換算呢?它是將全世界分為24個時區&#xff0c;地球的東、西經各180(共360)被24個時區平分&#xff0c;每個時區各占15。以經度0(即本初子午線)為基準&#xff0c;東經730′與西經730′之間的區域為零時區&#xff1b;東經和西經的730′與2230′之…

JS——實現短信驗證碼的倒計時功能(沒有驗證碼,只有倒計時)

1、功能描述 當用戶想要獲取驗證碼時&#xff0c;就點擊 免費獲取驗證碼 &#xff0c;然后開始倒計時&#xff0c;倒計時期間按鈕文字為剩余時間x秒&#xff0c;且不可按狀態&#xff0c;倒計時結束后&#xff0c;按鈕更改為點擊重新發送。 2、分析 必須用到定時器。按鈕點擊后…

華為OV小米鴻蒙,華為鴻蒙開源,小米OV們會采用嗎?

華為曾一直聲言不會進入電視市場,由此其他國產電視企業才會采用華為的可見企業是非常擔憂同業競爭關系的,而在智能手機市場,華為毫無疑問與其他國產手機企業都是競爭對手,更何況就在2019年下半年和2020年上半年華為在國內手機市場的份額超過四成直逼五成,其他國產手機企業被壓得…

第22天:如何使用OpenAI Gym和Universe構建AI游戲機器人

by Harini Janakiraman通過哈里尼賈納基拉曼 第22天&#xff1a;如何使用OpenAI Gym和Universe構建AI游戲機器人 (Day 22: How to build an AI Game Bot using OpenAI Gym and Universe) Let’s face it, AI is everywhere. A face-off battle is unfolding between Elon Musk…

軟件測試基礎理論(總結)

1&#xff0e; 軟件的三個要素&#xff1a;程序&#xff08;實行特定功能的代碼&#xff09; 文檔&#xff08;支持代碼運行&#xff09; 數據&#xff08;支持程序運行一切有關&#xff09; 2&#xff0e; 軟件的產品質量 指的是&#xff1f; 1&#xff09;質量是指實體特性…

android studio 7200u,#本站首曬# 多圖殺貓 華為MateBook X上手體驗

#本站首曬# 多圖殺貓 華為MateBook X上手體驗2017-06-09 18:45:4437點贊33收藏78評論前幾天華為開了個發布會&#xff0c;帶來了三款筆記本電腦&#xff0c;有幸在第一時間借到了MateBook X&#xff0c;現在就來來做一個簡單的上手&#xff0c;稍晚一些再跟大家詳細聊聊使用起來…

svn強制解鎖的幾種做法

標簽&#xff1a; svn強制解鎖2013-12-16 17:40 12953人閱讀 評論(0) 收藏 舉報分類&#xff1a;SoftwareProject&#xff08;23&#xff09; 版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主允許不得轉載。 作者&#xff1a;朱金燦 來源&#xff1a;http://blog.…