遍曆Linux kernel的鏈表時刪除元素的方法

來源:互聯網
上載者:User

<!--@page { 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也一樣。

 

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

       如,在java的遍曆中刪除當前元素,會拋出java.util.ConcurrentModificationException異常。

見:《Java中如何刪除一個集合中的多個元素》http://blog.csdn.net/shendl/archive/2007/12/28/1999907.aspx
一文。

 

 

       使用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. */#define list_for_each(pos, head) /        for (pos = (head)->next; prefetch(pos->next), pos != (head); /                pos = pos->next)

 

          list_del脫鏈元素後,會把next和prev分別賦值為:

/* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA

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

 

          因此,在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. */#define list_for_each_safe(pos, n, head) /        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可能已經是null 指標,或者是LIST_POISON1
這個無意義的值了。

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

 因此,使用lisf_for_each_safe函數遍曆list_head鏈表,就可以安全地刪除當前元素了。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.