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


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

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

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