最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux 內(nèi)核通用鏈表學(xué)習(xí)小結(jié)

 更新時間:2017年11月07日 11:57:18   作者:簡單方式  
本篇文章主要介紹了Linux 內(nèi)核通用鏈表學(xué)習(xí)小結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

描述

在linux內(nèi)核中封裝了一個通用的雙向鏈表庫,這個通用的鏈表庫有很好的擴展性和封裝性,它給我們提供了一個固定的指針域結(jié)構(gòu)體,我們在使用的時候,只需要在我們定義的數(shù)據(jù)域結(jié)構(gòu)體中包含這個指針域結(jié)構(gòu)體就可以了,具體的實現(xiàn)、鏈接并不需要我們關(guān)心,只要調(diào)用提供給我們的相關(guān)接口就可以完成了。

傳統(tǒng)的鏈表結(jié)構(gòu)

struct node{
  int key;
  int val;
  node* prev;
  node* next;
 }

linux 內(nèi)核通用鏈表庫結(jié)構(gòu)

提供給我們的指針域結(jié)構(gòu)體:

struct list_head {
  struct list_head *next, *prev;
};

我們只需要包含它就可以:

struct node{
  int val;
  int key;
  struct list_head* head;
}

可以看到通過這個 list_head 結(jié)構(gòu)就把我們的數(shù)據(jù)層跟驅(qū)動層分開了,而內(nèi)核提供的各種操作方法接口也只關(guān)心 list_head 這個結(jié)構(gòu),也就是具體鏈接的時候也只鏈接這個list_head 結(jié)構(gòu),并不關(guān)心你數(shù)據(jù)層定義了什么類型.

一些接口宏定義

//初始化頭指針
#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
  struct list_head name = LIST_HEAD_INIT(name)

//遍歷鏈表
#define __list_for_each(pos, head) \
  for (pos = (head)->next; pos != (head); pos = pos->next)

//獲取節(jié)點首地址(不是list_head地址,是數(shù)據(jù)層節(jié)點首地址)
#define list_entry(ptr, type, member) \
  container_of(ptr, type, member)

//container_of在Linux內(nèi)核中是一個常用的宏,用于從包含在某個
//結(jié)構(gòu)中的指針獲得結(jié)構(gòu)本身的指針,通俗地講就是通過結(jié)構(gòu)體變
//量中某個成員的首地址進(jìn)而獲得整個結(jié)構(gòu)體變量的首地址
#define container_of(ptr, type, member) ({     \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);  \
    (type *)( (char *)__mptr - offsetof(type,member) );})

#define offsetof(s,m) (size_t)&(((s *)0)->m)

使用方式

typedef struct node{
  int val;
  int key;
  struct list_head* list;
}node;

//初始化頭指針
LIST_HEAD(head);

//創(chuàng)建節(jié)點
node* a = malloc(sizeof(node));
node* b = malloc(sizeof(node));

//插入鏈表 方式一
list_add(&a->list,&head);
list_add(&b->list,&head);

//插入鏈表 方式二
list_add_tail(&a->list,&head);
list_add_tail(&b->list,&head);

//遍歷鏈表  
struct list_head* p;
struct node* n;
__list_for_each(p,head){
  //返回list_head地址,然后再通過list_head地址反推
  //節(jié)點結(jié)構(gòu)體首地址.
  n = list_entry(pos,struct node,list);
}

list_add 接口,先入后出原則,有點類似于棧

list_add-先入后出模式

list_add_tail 接口,先入先出原則,有點類似于fifo

list_add-先入先出模式

我們的鏈表節(jié)點,實際在內(nèi)存中的展示形態(tài)

節(jié)點描述

可以看到最終的形態(tài)是,通過指向每個結(jié)構(gòu)體里面的 list_head 類型指針,然后把它們串聯(lián)起來的

list_entry 接口,通過結(jié)構(gòu)體變量某個成員的地址,反推結(jié)構(gòu)體首地址,就像 __list_for_each 接口只返回 list_head 地址,所以我們要通過這個成員地址在去獲取它本身的結(jié)構(gòu)體首地址,底層實現(xiàn)方法 container_of 宏

反推結(jié)構(gòu)體首地址

舉個例子

這個例子包括簡單的增、刪、遍歷

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/init.h> 
#include <linux/slab.h> 
#include <linux/list.h> 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("David Xie"); 
MODULE_DESCRIPTION("List Module"); 
MODULE_ALIAS("List module"); 
 
struct student //代表一個實際節(jié)點的結(jié)構(gòu) 
{ 
  char name[100]; 
  int num; 
  struct list_head list;  //內(nèi)核鏈表里的節(jié)點結(jié)構(gòu) 
}; 
 
struct student *pstudent;    
struct student *tmp_student; 
struct list_head student_list;  
struct list_head *pos; 
 
int mylist_init(void) 
{ 
  int i = 0; 
   
  //初始化一個鏈表,其實就是把student_list的prev和next指向自身 
  INIT_LIST_HEAD(&student_list);  
   
  pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL);//向內(nèi)核申請5個student結(jié)構(gòu)空間 
  memset(pstudent,0,sizeof(struct student)*5); //清空,這兩個函數(shù)可以由kzalloc單獨做到 
   
  for(i=0;i<5;i++) 
  { //為結(jié)構(gòu)體屬性賦值 
    sprintf(pstudent[i].name,"Student%d",i+1); 
    pstudent[i].num = i+1;  
    //加入鏈表節(jié)點,list_add的話是在表頭插入,list_add_tail是在表尾插入 
    list_add( &(pstudent[i].list), &student_list);//參數(shù)1是要插入的節(jié)點地址,參數(shù)2是鏈表頭地址 
  }  
   
  list_for_each(pos,&student_list) //list_for_each用來遍歷鏈表,這是個宏定義 
                   //pos在上面有定義 
  { 
    //list_entry用來提取出內(nèi)核鏈表節(jié)點對應(yīng)的實際結(jié)構(gòu)節(jié)點,即根據(jù)struct list_head來提取struct student 
    //第三個參數(shù)list就是student結(jié)構(gòu)定義里的屬性list 
    //list_entry的原理有點復(fù)雜,也是linux內(nèi)核的一個經(jīng)典實現(xiàn),這個在上面那篇鏈接文章里也有講解 
    tmp_student = list_entry(pos,struct student,list); 
    //打印一些信息,以備驗證結(jié)果 
    printk("<0>student %d name: %s/n",tmp_student->num,tmp_student->name); 
  } 
   
  return 0; 
} 
 
 
void mylist_exit(void) 
{   
  int i ; 
  /* 實驗:將for換成list_for_each來遍歷刪除結(jié)點,觀察要發(fā)生的現(xiàn)象,并考慮解決辦法 */ 
  for(i=0;i<5;i++) 
  { 
    //額,刪除節(jié)點,只要傳個內(nèi)核鏈表節(jié)點就行了 
    list_del(&(pstudent[i].list));    
  } 
  //釋放空間 
  kfree(pstudent); 
} 
 
module_init(mylist_init); 
module_exit(mylist_exit); 

結(jié)束

linux 內(nèi)核提供的這個通用鏈表庫里面還有很多其他的接口,這里沒有詳細(xì)的一一舉例,有興趣的可以自己去看看,在源碼包 include/linux/list.h 文件里面,不過通過閱讀一些源代碼確實對我們也有很大的提高,可以看看高手是如何去設(shè)計并實現(xiàn),還可以學(xué)到一些技巧以及對代碼細(xì)節(jié)的掌握~~.

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • CentOS7下安裝yum源及上傳下載命令rz、sz安裝方法(圖解)

    CentOS7下安裝yum源及上傳下載命令rz、sz安裝方法(圖解)

    這篇文章主要介紹了CentOS7下安裝yum源及上傳下載命令rz、sz安裝方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • Polysh命令實現(xiàn)多日志查詢的方法示例

    Polysh命令實現(xiàn)多日志查詢的方法示例

    大家應(yīng)該都知道Polysh是一個交互式命令,可以在一臺服務(wù)器上批量的對一批服務(wù)器進(jìn)行處理,運行交互式命令。下面這篇文章主要給大家介紹了關(guān)于利用Polysh命令實現(xiàn)多日志查詢的相關(guān)資料,需要的朋友可以參考,下面來一起看看吧。
    2017-12-12
  • CentOS 7系統(tǒng)下安裝ftp服務(wù)器的全過程

    CentOS 7系統(tǒng)下安裝ftp服務(wù)器的全過程

    這篇文章主要介紹了關(guān)于CentOS 7系統(tǒng)下安裝ftp服務(wù)器的全過程,文中介紹的非常詳細(xì),詳細(xì)對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • linux服務(wù)器被植入ddgs、qW3xT.2挖礦病毒的處理實戰(zhàn)記錄

    linux服務(wù)器被植入ddgs、qW3xT.2挖礦病毒的處理實戰(zhàn)記錄

    這篇文章主要給大家介紹了關(guān)于linux服務(wù)器被植入ddgs、qW3xT.2挖礦病毒的處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2018-09-09
  • 淺談find命令下的atime,ctime,mtime

    淺談find命令下的atime,ctime,mtime

    下面小編就為大家?guī)硪黄獪\談find命令下的atime,ctime,mtime。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Linux常用命令mkdir詳解

    Linux常用命令mkdir詳解

    在Linux系統(tǒng)中,mkdir命令用來創(chuàng)建一個目錄或一個級聯(lián)目錄。那么具體如何使用呢,我們下面來探討下
    2018-04-04
  • LNMP下提示File not found問題的解決方法

    LNMP下提示File not found問題的解決方法

    這篇文章主要給介紹了關(guān)于在LNMP下提示File not found問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • Linux多線程鎖屬性設(shè)置方法

    Linux多線程鎖屬性設(shè)置方法

    下面小編就為大家?guī)硪黄狶inux多線程鎖屬性設(shè)置方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • 詳解linux dma驅(qū)動編寫

    詳解linux dma驅(qū)動編寫

    這篇文章主要介紹了詳解linux dma驅(qū)動編寫,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Linux 下C語言連接mysql實例詳解

    Linux 下C語言連接mysql實例詳解

    這篇文章主要介紹了Linux 下C語言連接mysql實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-04-04

最新評論

绵阳市| 兰西县| 北宁市| 镇平县| 库车县| 齐河县| 九寨沟县| 柳江县| 岳西县| 延吉市| 清远市| 台州市| 靖远县| 丰台区| 双峰县| 安仁县| 濮阳县| 杂多县| 庆云县| 波密县| 桐庐县| 澄城县| 南通市| 儋州市| 天祝| 上饶市| 澄江县| 巴彦县| 五华县| 明水县| 浦北县| 南汇区| 丹江口市| 湾仔区| 长沙县| 定结县| 扎鲁特旗| 茶陵县| 肇庆市| 平泉县| 永年县|