只考慮單鏈表,直接對各種情況進行分析,
對於Insert,需要關注的點在於,先要對new_node 進行初始化。且Insert的時候要加鎖,意味着同時只有一個元素寫鏈表。至於爲什麼看後面的圖吧,深入理解linux內核講的挺好的。
void InsertList(ListNode *new_node, ListNode* prev , ListNode *next) {
new_node->next = next;
wmb();
prev->next = new_node;
}
對於read,需要關注點的在於,設置寬限期,使得delete的時候,等待read結束,但是read不需要加鎖
void ForeachList(ListNode *head) {
p = head;
while (p) {
rcu_lock(p);// rcu的關鍵,在讀的時候不設置臨界區,只設置寬限期,等讀操作結束的時候,可以刪除操作,可以理解爲對一個原子變量++
fun(p);
p1 = p->next;
rcu_unlock(p);// 可以替換對一個原子變量-
p = p1;
}
}
delete的時候做的操作如下
prev, next = seach_the_entry_to_delete(p);//搜索要刪的節點,
list_del_rcu(prev,next); //實際這塊內存還在, 只是從prev的時候,有些線程會訪問到next指針而不是p
synchronize_rcu(p); // 標記這快內存還在用,等待用完,等於循環判斷上述原子變量等不等於0
free(p);
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
prev->next = next;
}
對於unpate操作就相對簡單了, 有些線程會訪問到q指針而不是p
p = search_the_entry_to_update();
q = kmalloc(sizeof(*p), GFP_KERNEL);
*q = *p;
q->field = new_value;
list_replace_rcu(&p->list, &q->list);
synchronize_rcu();
kfree(p);
static inline void list_replace_rcu( prev)
{
prev->next = q;;
}
從整體來說,update,delete,insert還是要加入指針的, 但是read的時候是直接讀。