一文解決RCU機制及內(nèi)存優(yōu)化屏障
RCU機制
RCU英文全稱為Read-Copy-Update,顧名思義就是 “讀 - 拷貝-更新”,是內(nèi)核中重要的同步機制。
RCU原理
RCU記錄所有指向共享數(shù)據(jù)的指針的使用者,當要修改該共享數(shù)據(jù)時,首先創(chuàng)建一個副本,在副本中修改。所有讀訪問線程都離開讀臨界區(qū)之后 ,指針指向新的修改后副本的指針,并且刪除舊數(shù)據(jù)。
寫著修改過程:首先賦值生成一個副本,然后更新副本,最后使用新的對象代替舊的對象。在寫者執(zhí)行復制更新時候讀者可以讀數(shù)據(jù)。
寫者刪除對象,必須等到所有訪問被刪除對象的讀者訪問結(jié)束,才能夠執(zhí)行銷毀操作。RCU關鍵技術是怎么判斷所有讀者已經(jīng)訪問完成。等待所有讀者訪問結(jié)束的時間稱為寬限期(grace period)。
RCU讀者并不需要直接與寫者進行同步。讀者與寫者也能并發(fā)執(zhí)行。RCU目標最大程度來減少讀者開銷。經(jīng)常適用于讀者性能要求高的場景。
RCU優(yōu)先:讀者開銷少;不需要任何鎖,不需要執(zhí)行原子指令或者內(nèi)存屏障;沒有死鎖;沒有優(yōu)先級反轉(zhuǎn)的問題;沒有內(nèi)存泄漏的危險問題;很好的實時延遲操作。
RCU缺點:寫者的同步開銷比較大,寫者之間需要互斥處理;使用其它同步機制復雜。
RCU應用場景: 例如:每種鎖都有自己適合的場景:spin lock不區(qū)分reader/writer,對于讀寫強度不對稱是不適合的,RW spin lock和seq lock解決了這個問題,seq lock傾向于writer, RW spin lock傾向于reader。 a. RCU只能保護動態(tài)分配的數(shù)據(jù)結(jié)構(gòu),并且必須是通過指針訪問該數(shù)據(jù)結(jié)構(gòu); b. 受RCU保護的臨界區(qū)不能sleep; c. 讀寫不對稱,對writer的性能沒有特別的要求,但是reader性能要求極高; d. reader端對新舊數(shù)據(jù)不敏感。 RCU適用于需要頻繁的讀取數(shù)據(jù),而且相應修改數(shù)據(jù)并不多的場景。例如:文件系統(tǒng)中,搜索定位目錄,而對于目錄修改相對來講基本沒用。
【文章福利】小編推薦自己的Linux內(nèi)核技術交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)??


?
鏈表操作
RCU能保護的不僅僅是一般的指針。內(nèi)核也提供標準函數(shù),使得能通過RCU機制保護 雙鏈表,這是RCU機制在內(nèi)核內(nèi)部最重要的應用。
對于writer,RCU操作包括:
rcu_assign_pointer 該函數(shù)被writer用來進行removal操作,在writer完成新版數(shù)據(jù)分配和更新之后,調(diào)用這個函數(shù)可以記RCU protected pointer指向RCU protected data。
synchronize_rcy: writer端操作可以是同步的,也就是說,完成更新操作之后,可以調(diào)用這個函數(shù)等到所有舊版本數(shù)據(jù)上的reader線程離開臨界區(qū),一旦從函數(shù)返回,說明就得共享數(shù)據(jù)沒有任何引用,直接進行reclaimation的操作。
call_rcu:writer無法阻塞,可以調(diào)用call_rcu接口函數(shù),該函數(shù)是注冊callback直接返回,在適當實際會調(diào)用callback函數(shù),完成reclaimation。

removal:write分配一個new version共享數(shù)據(jù)進行數(shù)據(jù)更新,更新完畢后將pointer指向新版本的數(shù)據(jù),通過這樣的操作,原來reader0 reader1對共享數(shù)據(jù)的引用被刪除。 reclamation:共享數(shù)據(jù)不能有兩個版本,一定要在適當?shù)亩鴮嶋H回收舊版本數(shù)據(jù)。
RCU層次架構(gòu)
RCU根據(jù)CPU數(shù)量的大小按照樹形結(jié)構(gòu)來自成其層次結(jié)構(gòu),稱為RCU Hierarchy。
【32核處理器的CPU層次結(jié)構(gòu)】 兩個層次,level0 包含兩個struct rcu_node, 每個struct rcu_node管理16個struct rcu_data數(shù)據(jù)結(jié)構(gòu),分別表示16個CPU獨立的struct rcu_data數(shù)據(jù)結(jié)構(gòu);在level1層級,有一個struct rcu_node節(jié)點管理level0層級的兩個rcu_node節(jié)點,level1層級中的rcu_node節(jié)點稱為根節(jié)點,level0層級的連個rcu_node節(jié)點是葉子節(jié)點。

優(yōu)化屏障
編譯器優(yōu)化:提高系統(tǒng)性能,編譯器在不影響邏輯的情況下會調(diào)整指令的順序。
CPU執(zhí)行優(yōu)化:提高流水線性能,CPU的亂序執(zhí)行可能會讓后面的沒有寄存器沖突和匯編指令優(yōu)于前面的指令完成。
優(yōu)化屏障避免編譯的重新排序優(yōu)化操作,保證編譯程序時在優(yōu)化屏障之前的指令不會 在優(yōu)化屏障之后執(zhí)行。
內(nèi)存屏障
內(nèi)存屏障,也稱內(nèi)存柵障或屏障指令等,是一類同步屏障指令,是編譯器或CPU對內(nèi)存訪問操作的時候,嚴格按照一定順序來執(zhí)行,也就是memory barrier之前的指令和memory barrier之后的指令不會由于系統(tǒng)優(yōu)化等原因而導致亂序。 memory barrier包括兩類:編譯器屏障(complier barrier)和CPU屏障(cpu barrier)
CPU內(nèi)存屏障:防止指令之間重排序;保證數(shù)據(jù)可見性。
分類:
mb()/rmab()/wmb()將硬件內(nèi)存屏障插入到代碼流程中,barrier插入一個優(yōu)化屏障,該指令告知編譯器,保存在CPU寄存器中、在屏障之前有效的所有內(nèi)存地址,在屏障之后全部消失。本質(zhì),編譯器在屏障之前發(fā)出的讀寫請求完成之前,會處理屏障之后的任何讀寫請求。 smp_mp()/smp()_rmb()/smp_wmb()相當于硬件內(nèi)存屏障,只適用于SMP系統(tǒng)。在單處理器系統(tǒng)上產(chǎn)生的是軟件屏障。 內(nèi)存屏障作用:解決CPU高速緩存存在的問題,無鎖數(shù)據(jù)結(jié)構(gòu),內(nèi)存屏障很有用處。
總結(jié)
本文主要介紹了RCU機制,包括原理、鏈表操作、層次架構(gòu)、32核處理器的CPU層次結(jié)構(gòu),及內(nèi)存屏障,包括編譯器屏障、CPU屏障等。
