1. 程式人生 > >遍歷Linux kernel的連結串列時刪除元素的方法

遍歷Linux kernel的連結串列時刪除元素的方法

<[email protected] { margin: 2cm }PRE.cjk { font-family: "DejaVu Sans", monospace }P { margin-bottom: 0.21cm }A:link { so-language: zxx }-->

         核心的連結串列list_head設計相當巧妙。今天我說一下對list_head連結串列的遍歷時如何刪除元素。

         連結串列遍歷時,如果刪除當前元素,一般都是會出錯的。在所有語言的各種庫中的連結串列都是如此。list_head也一樣。

<[email protected]

{ margin: 2cm }P { margin-bottom: 0.21cm }A:link { so-language: zxx }-->

       如,在java的遍歷中刪除當前元素,會丟擲java.util.ConcurrentModificationException異常。

       使用list_for_each遍歷連結串列,如果使當前元素脫鏈,那麼系統就會毫不留情的crash掉。什麼提示資訊都沒有。因此這類bug非常難以定位。

list_for_each原始碼:

/**
* list_for_each        -       iterate over a list
* @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ for (pos = (head)->next; prefetch(pos->next), pos != (head); / pos = pos->next)

          list_del脫鏈元素後,會把nextprev分別賦值為:

/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses * non-initialized list entries. */

       list_del_init脫鏈元素後,會把nextprev都設定為自己。

          因此,在list_for_each中刪除當前元素後,就無法正確找到連結串列的下一個元素。

       如果要在遍歷list_head連結串列時,刪除當前元素,那麼就必須使用list_for_each_safe函式而不能使用list_for_each函式。

list_for_each_safe原始碼:

/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos:        the &struct list_head to use as a loop cursor.
* @n:          another &struct list_head to use as temporary storage
* @head:       the head for your list.
*/

        for (pos = (head)->next, n = pos->next; pos != (head); /
                pos = n, n = pos->next)

          這個函式比list_for_each函式多了一個n引數。這個引數也是list_head型別的。

          它儲存下一個元素,這樣就可以安全的刪除當前元素,不會造成找不到後續元素的情況發生。

          在迴圈結束時,pos指向n元素,而不是指向posnext元素。因為pos脫鏈後,pos元素的next可能已經是空指標,或者是這個無意義的值了。

         如果list是空的,那麼pos=n後,仍然等於head,遍歷就此結束了!

因此,使用lisf_for_each_safe函式遍歷list_head連結串列,就可以安全地刪除當前元素了。

相關推薦

Linux kernel連結串列刪除元素方法

<[email protected] { margin: 2cm }PRE.cjk { font-family: "DejaVu Sans", monospace }P { margin-bottom: 0.21cm }A:link { so-languag

java實現---查詢單鏈表的倒數第K個節點,要求只能一次連結串列;;;刪除連結串列的倒數第k個節點

java實現 查詢單鏈表的倒數第K個節點,要求只能遍歷一次連結串列 刪除連結串列的倒數第k個節點 查詢單鏈表的倒數第K個節點,要求只能遍歷一次連結串列 定義兩個前後節點forward和backward 先

C++ 連結串列的基本操作:頭插入、尾插入、、判斷連結串列是否為空、清空、求長度、插入、刪除、逆置連結串列和排序

// // main.cpp // List: // 連結串列的操作: // 1.頭插入 // 2.尾插入建立連結串列; // 3.遍歷連結串列; // 4.連結串列是否為空 // 5.清空連結串列 // 6.求連結串列的長度 // 7.

有向圖的建立與(鄰接連結串列

下面介紹一下,有向圖的建立與遍歷(使用鄰接連結串列法) 思路:在頂點結構體裡面,將第一條邊用指向邊的結構體的指標firstedge儲存 即struct EdgeNode * next; 1.再輸入,邊的個數,頂點的個數。 2.輸入所有節點的字母 3.最後再輸入所有的邊的字母(例如,輸入

查詢單鏈表的倒數第k個結點,要求只能一次連結串列

pNode FindLastKNode(pList plist, int k) { pNode pFast = plist; pNode pSlow = plist; if (plist == NULL || k <= 0) { return NULL;

java實現---查詢單鏈表的中間節點,要求只能一次連結串列

定義兩個節點,一個快,一個慢 快的一次走兩步;慢的一次走一步 當快的走到連結串列的最後時,慢的剛好走到一半,即連結串列的中間節點 class ListNode{ int data; ListNode next; } public class

查詢單鏈表的倒數第k個節點,要求只能一次連結串列

為了得到倒數第k個結點,很自然的想法是先走到連結串列的尾端,再從尾端回溯k步。可是輸入的是單向連結串列,只有從前往後的指標而沒有從後往前的指標。因此我們需要開啟我們的思路。既然不能從尾結點開始遍歷這個連結串列,我們還是把思路回到頭結點上來。假設整個連結串列有n個

查詢單鏈表的中間結點,要求只能一次連結串列

pNode FindMiddleNode(pList plist) { /* 快慢指標,快的兩步,慢的一步 */ pNode pFast = plist; pNode pSlow = plist; while (pFast&&pFast->n

建立和單向線性連結串列(C)

連結串列(Linked List)是由節點組成的(node)。而節點實質上是一個數據結構(struct or class)。連結串列和陣列(Array)的區別在於連結串列中的節點在記憶體中的位置不一定是連續的,並且節點個數無需在編譯時確定。 節點包含兩種資訊,一種是資

無向圖的深度優先和廣度優先(鄰接連結串列

我選的是鄰接連結串列,建立如下圖所示的圖: 我把它畫出來,圖是這樣子的: 對於深度優先遍歷:是從一個頂點v出發,一步一步地向前推進,當找不到未訪問過的頂點時,也是一步一步地回退。其過程類似於用棧求解迷宮問題的搜尋方式。 比如上面這個圖:我從4這個頂點開始遍歷,它

集合過程iterator, 添加刪除元素報異常

exc asn 一致性 使用 遍歷 one mov exceptio 刪除 list set 遍歷過程中添加或者刪除元素,報異常。 使用iterator 也會報異常 ConcurrentModificationException remove只能用叠代器的remov

遞迴呼叫:連結串列刪除元素不斷鏈現象

刪除的程式碼: void del(NodeList &L, ElemType x){     NodeList p;     if(L!=NULL)         if(L->dat

Java 中list(ArrayList)的foreach方式呼叫list的remove刪除元素,不丟擲ConcurrentModificationException

關於list刪除元素的當時有很多,具體可以參考下面這個部落格。 https://blog.csdn.net/claram/article/details/53410175 裡面提到了list的foreach遍歷方式刪除元素,會丟擲ConcurrentMo

用結構體實現連結串列的建立、、結點插入、結點刪除連結串列刪除-----帶選單選項

#include <iostream> using namespace std; enum operation{create_List=1,print_List,insert_Node,delete_Node,delete_List,quit};//列舉型別,

(補充實驗方法) linux核心連結串列之例項 這個例子包括簡單的增、刪、

#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/list.h>MODUL

Python列表刪除元素

bsp lam 簡潔 log ref body 同時 http 兩個 無論是使用for還是while,當在從前往後遍歷的同時刪除列表中的元素時,都會發生些問題。 要從lst = [1,4,0,1,5,0,3,5]中刪除所有0元素,有兩個比較好的方法: 1 使用filter:

Python--列表刪除元素的正確做法

一.問題描述  這是在工作中遇到的一段程式碼,原理大概和下面類似(判斷某一個元素是否符合要求,不符合刪除該元素,最後得到符合要求的列表): a = [1,2,3,4,5,6,7,8] for i in a: if i>5: pass else:

集合刪除元素,丟擲java.util.ConcurrentModificationException的解決辦法

遍歷集合刪除其中的元素時可能會丟擲java.util.ConcurrentModificationException異常。 下面的程式碼就會丟擲異常: 1: for (String s : map.keySet()) { 2: if ("val".

Python -- 字典刪除元素報異常

錯誤的程式碼①d = {'a':1, 'b':0, 'c':1, 'd':0} for key, val in d.items(): del(d[key])錯誤的程式碼② -- 對於Python

list刪除元素的正確做法

我們往往會遇到需要刪除list中滿足條件的元素。舉例: List<string> list_str =new List<string>() { "A","B","B",