链表遍历时,如果删除当前元素,一般都是会出错的。在所有语言的各种库中的链表都是如此。list_head也一样。
使用list_for_each遍历链表,如果使当前元素脱链,那么系统就会毫不留情的crash掉。什么提示信息都没有。因此这类bug非常难以定位。
list_for_each源码:
list_del脱链元素后,会把next和prev分别赋值为:
list_del_init脱链元素后,会把next和prev都设置为自己。
因此,在list_for_each中删除当前元素后,就无法正确找到链表的下一个元素。
如果要在遍历list_head链表时,删除当前元素,那么就必须使用list_for_each_safe函数而不能使用list_for_each函数。
list_for_each_safe源码:
这个函数比list_for_each函数多了一个n参数。这个参数也是list_head类型的。
它保存下一个元素,这样就可以安全的删除当前元素,不会造成找不到后续元素的情况发生。
在循环结束时,pos指向n元素,而不是指向pos的next元素。因为pos脱链后,pos元素的next可能已经是空指针,或者是LIST_POISON1 这个无意义的值了。
如果list是空的,那么pos=n后,仍然等于head,遍历就此结束了!