對於RCU的衍生思考-- 設計一個線程安全的鏈表

只考慮單鏈表,直接對各種情況進行分析,
對於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的時候是直接讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章