經典同步問題與並行程式設計

讀-複製-更新(read-copy-update)

/ RCU -> ar-see-YOO /

讀-複製-更新,幾乎總是縮寫為 RCU,是一種針對「讀取極頻繁、寫入極稀少」資料的同步技術。日常的畫面是貼在牆上的公車時刻表。數百名乘客自由地、同時地閱讀它,零協調、零等待——讀取毫無成本。當班表更動時,運輸單位不會在大家正讀時把貼著的那份擦掉。它改為印出一份全新的更新版,再悄悄把新的換上、取代舊的。任何正讀到一半舊版的人都能無害地把它讀完;新讀者則看到新版。舊版唯有在確定沒人還在看它之後才被丟棄。

在機制上,RCU 讓讀者極其廉價——讀者通常完全不取鎖,只標記一段輕量的讀端臨界區間,因此並行的讀取彼此之間、以及與寫者之間都永不阻塞。想更動某節點的寫者不會就地修改它(那可能被讀者抓到改到一半)。它改為做一份私有副本、修改副本,再原子地交換一個指標使其指向新版。既有的讀者照樣繼續走訪舊版;未來的讀者則沿著指標走到新版。微妙之處在於回收:寫者必須等待一個寬限期(grace period)——長到足以讓每一個可能持有舊版引用的讀者都已完成——才能安全地釋放那個舊版。RCU 用靜止狀態(quiescent state,已知某 CPU 不持有任何 RCU 保護引用的時刻)的概念來追蹤這點。

RCU 在讀為主的工作負載上大放異彩,在 Linux 核心內部正是為這類情況而被大量使用(路由表、目錄項目快取、已載入模組的清單),它帶來近乎零的讀取開銷與優異的多核可擴展性。誠實的取捨:寫者更昂貴也更複雜(複製、交換、再熬過一個寬限期)、更新是延後而非即時、且在交換的時間視窗內讀者可能看到舊版或新版——所以 RCU 適合那種「短暫讀到略為過時但仍一致的資料」可被接受的資料。當寫入頻繁、或讀者必須永遠看到最新值時,它並不是一把鎖的即插即用替代品。

在 RCU 下更新一個串列節點:copy = clone(node); modify(copy); atomic_swap(pointer, copy);接著 synchronize_rcu() 熬過寬限期;最後 free(oldNode)。整個過程中讀者只是不取鎖地對指標解參考。

寫者先複製再交換,並延後釋放,直到一個寬限期證明沒有讀者還持有舊版。

RCU 適用於讀為主的資料,並假設讀者能容忍短暫看到略舊(但內部一致)的版本。當寫入頻繁時,它的寬限期與複製開銷可能讓它比單純的鎖還慢。

又称
RCU讀複製更新