重要的抽象和數(shù)據(jù)結(jié)構(gòu)
TaskRunner和SequencedTaskRunner和SingleThreadTaskRunner
用于發(fā)布由TaskRunner運行的base :: Callbacks“任務(wù)”的接口。TaskRunner不保證執(zhí)行(順序免绿,并發(fā)性鞠眉,甚至根本不執(zhí)行)剥扣。SequencedTaskRunner提供有關(guān)執(zhí)行順序的某些保證(大致來說是FIFO硝皂,但如果感興趣仍秤,請參見標頭中的詳細內(nèi)容),并且SingleThreadTaskRunner提供與SequencedTaskRunner相同的保證,除了所有任務(wù)都在同一線程上運行逼裆。MessageLoopProxy是SingleThreadTaskRunner的規(guī)范示例。這些接口對于通過依賴項注入進行測試也很有用赦政。 注意: 成功發(fā)布到TaskRunner并不一定意味著該任務(wù)將運行胜宇。
注意: TaskRunner的一個非常有用的成員函數(shù)是PostTaskAndReply(),該函數(shù)會將任務(wù)發(fā)布到目標TaskRunner恢着,并在完成時將“答復(fù)”任務(wù)發(fā)布到原始TaskRunner桐愉。
MessageLoop 和 MessageLoopProxy 和BrowserThread 和RunLoop
這些是用于發(fā)布任務(wù)的各種API。MessageLoop是MessageLoopProxy(在Chromium代碼中使用最廣泛的任務(wù)運行程序)使用的具體對象然评。您幾乎應(yīng)該總是使用MessageLoopProxy而不是MessageLoop仅财,或者如果您使用的是chrome或content,則可以使用BrowserThread碗淌。這是為了避免在破壞MessageLoop方面發(fā)生爭執(zhí)盏求,因為如果基礎(chǔ)MessageLoop已被破壞,則MessageLoopProxy和BrowserThread將刪除該任務(wù)亿眠。 注意: 成功發(fā)布到MessageLoop(Proxy)不一定意味著任務(wù)將運行碎罚。
PS:關(guān)于何時使用SequencedTaskRunner,MessageLoopProxy和BrowserThread纳像,存在一些爭論荆烈。使用諸如SequencedTaskRunner之類的接口類可使代碼更加抽象/可重用/可測試。另一方面竟趾,由于額外的間接層憔购,它使代碼不那么明顯。盡管可以說您可以適當?shù)孛鸖equencedTaskRunner變量以使其更加清晰岔帽,但使用具體的BrowserThread ID可以立即清楚地知道它在哪個線程上運行玫鸟。當前的決定是僅在必要時將代碼從BrowserThread轉(zhuǎn)換為TaskRunner子類型。MessageLoopProxy應(yīng)該始終作為SingleThreadTaskRunner或父接口(如SequencedTaskRunner)傳遞犀勒。
base :: SequencedWorkerPool和base :: WorkerPool
這是Chromium中的兩個主要工作人員池屎飘。SequencedWorkerPool是一個更復(fù)雜的工作池,它繼承自TaskRunner贾费,并提供了按順序排序任務(wù)的方式(通過共享SequenceToken)钦购,并且還指定了關(guān)閉行為(阻止執(zhí)行任務(wù),如果瀏覽器正在關(guān)閉褂萧,則不要運行該任務(wù)押桃,并且它尚未啟動,但是否已阻止它箱玷,或者允許該任務(wù)運行怨规,而與瀏覽器關(guān)閉無關(guān)陌宿,也不要阻止它關(guān)閉)。SequencedWorkerPool還提供了一種基于SequenceToken返回SequencedTaskRunner的功能波丰。在所有主瀏覽器線程(主線程除外)都停止之后壳坪,Chromium瀏覽器進程將關(guān)閉base :: SequencedWorkerPool。base :: WorkerPool是一個全局對象掰烟,不會在瀏覽器進程關(guān)閉時關(guān)閉爽蝴,因此它上運行的所有任務(wù)都不會加入。通常不建議使用base :: WorkerPool纫骑,因為任務(wù)可能依賴于其他對象蝎亚,這些對象可能會在瀏覽器關(guān)閉期間被銷毀。
base :: Callback和base :: Bind()
base :: Callback是一組內(nèi)部引用的模板化回調(diào)類先馆,它們具有不同的Arities和返回值(包括void)发框。請注意,這些回調(diào)是可復(fù)制的煤墙,但共享(通過refcounting)函數(shù)指針和綁定參數(shù)的內(nèi)部存儲梅惯。base :: Bind()將把參數(shù)綁定到一個函數(shù)指針(在幕后,它將函數(shù)指針和所有參數(shù)復(fù)制到內(nèi)部引用存儲對象中)并返回base :: Callback仿野。
如果函數(shù)是成員函數(shù)铣减,則base :: Bind()會自動將第一個參數(shù)添加到AddRef()/ Release(),如果未重新引用類型脚作,它將抱怨(避免base :: WeakPtr或base :: Unretained()出現(xiàn)此問題) )葫哗。同樣,對于函數(shù)參數(shù)球涛,它將使用COMPILE_ASSERT嘗試驗證它們是否不是指向refcounted類型的原始指針(僅在具有完整類型信息的情況下才可用劣针,而不在前向聲明中)。而是使用scoped_refptrs或調(diào)用make_scoped_refptr()來防止bug亿扁。另外酿秸,base :: Bind()理解base :: WeakPtr。如果函數(shù)是成員函數(shù)魏烫,并且第一個參數(shù)是對象的base :: WeakPtr,則base :: Bind()將注入包裝器函數(shù)肝箱,僅當base :: WeakPtr為非NULL時才調(diào)用函數(shù)指針哄褒。base :: Bind()還具有以下用于參數(shù)的輔助包裝器。
- base :: Unretained()-禁用成員函數(shù)接收器對象(可能不是refcounted類型)和函數(shù)參數(shù)上的COMPILE_ASSERT的refcounting煌张。請謹慎使用呐赡,因為這意味著您需要確保對象的生存期可以超過調(diào)用回調(diào)的時間。對于成員函數(shù)接收者對象骏融,最好改用base :: WeakPtr链嘀。
- base :: Owned()-將原始指針的所有權(quán)轉(zhuǎn)移到返回的base :: Callback存儲中萌狂。這非常有用,因為不能保證TaskRunners在關(guān)閉時運行回調(diào)(可能要刪除對象)怀泊,因此通過使回調(diào)擁有所有權(quán)茫藏,可以防止在不運行回調(diào)時煩人的關(guān)閉泄漏。
- base :: Passed()-用于將范圍對象(scoped_ptr / ScopedVector / etc)傳遞給回調(diào)霹琼。base :: Owned()和base :: Passed()之間的主要區(qū)別是base :: Passed()要求函數(shù)簽名將范圍類型作為參數(shù)务傲,從而允許 通過.release()轉(zhuǎn)移所有權(quán)。注意: 由于范圍類型的范圍是函數(shù)范圍枣申,因此這意味著base :: Callback只能被調(diào)用一次售葡。否則,這將是潛在的使用忠藤,可能需要經(jīng)過免費刪除和一定的兩次刪除挟伙。與base :: Owned()相比,鑒于base :: Passed()的語義復(fù)雜性模孩, 一般而言尖阔,您應(yīng)該更喜歡base :: Owned()而不是base :: Passed()。
- base :: ConstRef()-將參數(shù)作為const引用傳遞瓜贾,而不是將其復(fù)制到內(nèi)部回調(diào)存儲中诺祸。出于明顯的性能原因很有用,但通常不應(yīng)使用祭芦,因為它要求引用的生存期必須超過可以調(diào)用回調(diào)的時間筷笨。
- base :: IgnoreResult()-將其與傳遞給base :: Bind()的函數(shù)指針一起使用,以忽略結(jié)果龟劲。使回調(diào)可與僅使用閉包的TaskRunner一起使用(無參數(shù)或返回值的回調(diào))很有用胃夏。
scoped_refptr 和base :: RefCounted和base :: RefCountedThreadSafe
引用計數(shù)有時是有用的,但通常更表示有人沒有仔細考慮所有權(quán)昌跌。當所有權(quán)真正共享時(例如仰禀,多個選項卡共享同一個渲染器進程),而不是 在難以進行壽命管理的情況下蚕愤,可以使用它答恶。
單例&base :: LazyInstance
它們是全局變量,因此按照樣式指南萍诱,通常應(yīng)避免使用它們悬嗓。就是說,當您在Chromium代碼中使用全局變量時裕坊,通常最好使用其中之一包竹,通常,與Singleton相比,更喜歡使用base :: LazyInstance周瞎。使用這些類的原因是構(gòu)造是懶惰的(因此可以防止由于靜態(tài)初始化程序而導(dǎo)致啟動減慢)苗缩,并且銷毀順序是明確定義的。銷毀AtExitManager時声诸,銷毀它們的順序與構(gòu)造順序相反酱讶。在Chromium瀏覽器過程中,AtExitManager早在主線程(UI線程)中實例化双絮,因此浴麻,即使在不同的線程上構(gòu)建,所有這些對象也會在主線程上被銷毀囤攀。選擇base :: LazyInstance而不是base :: Singleton的原因是base :: LazyInstance通過保留數(shù)據(jù)段中的空間并使用new放置在該內(nèi)存位置中構(gòu)造對象來減少堆碎片软免。注意: Singleton和base :: LazyInstance都提供“泄漏”特征以在關(guān)閉時泄漏全局變量。通常建議這樣做(可能在庫代碼中除外焚挠,在庫代碼中可能會將代碼動態(tài)加載到另一個進程的地址空間中膏萧,或者在進程關(guān)閉時需要刷新數(shù)據(jù)時),以免減慢關(guān)閉速度蝌衔。對于這些“泄漏”特征榛泛,有valgrind抑制。
base :: Thread 和base :: PlatformThread
通常噩斟,您不應(yīng)該使用這些功能曹锨,因為您通常應(yīng)該將任務(wù)發(fā)布到現(xiàn)有TaskRunner上。PlatformThread是特定于平臺的線程剃允。base :: Thread包含在PlatformThread上運行的MessageLoop沛简。
base :: WeakPtr 和 base :: WeakPtrFactory
通常是線程不安全的弱指針,如果引用已被銷毀斥废,則返回NULL椒楣。跨線程傳遞(并在其他線程上銷毀)是安全的牡肉,但只應(yīng)在創(chuàng)建該線程的原始線程上使用捧灰。base :: WeakPtrFactory非常適合在base :: WeakPtr的引用被銷毀時自動取消base :: Callbacks。
文件路徑
文件路徑的跨平臺表示统锤。通常毛俏,您應(yīng)該使用它代替特定于平臺的表示形式。
ObserverList和ObserverListThreadSafe
ObserverList是一個線程不安全的對象饲窿,旨在用作類的成員變量拧抖。它提供了一個簡單的接口,用于迭代一堆Observer對象并調(diào)用通知方法免绿。
ObserverListThreadSafe類似。它包含多個ObserverLists擦盾,并且在注冊觀察者的同一PlatformThreadId上調(diào)用觀察者通知嘲驾,從而允許跨線程代理通知淌哟,并允許各個觀察者以單線程方式接收通知。
泡菜
Pickle提供了二進制形式的對象序列化和反序列化的基本工具辽故。
值
值允許指定包含簡單值(bool / int / string / etc)的遞歸數(shù)據(jù)類(列表和字典)徒仓。這些值也可以序列化為JSON并返回。
日志
這是登錄Chromium的基本接口誊垢。
FileUtilProxy
通常掉弛,您不應(yīng)該在對垃圾郵件敏感的線程(BrowserThread :: UI和BrowserThread :: IO)上執(zhí)行文件I / O,因此您可以通過這些實用程序?qū)⑺鼈兇淼搅硪粋€線程(例如BrowserThread :: FILE)喂走。
時間殃饿, TimeDelta, TimeTicks芋肠, 計時器
通常使用TimeTicks而不是Time來保持穩(wěn)定的滴答計數(shù)器(如果用戶更改計算機時鐘乎芳,則時間可能會更改)。
PrefService帖池,ExtensionPrefs
與用戶Profile關(guān)聯(lián)的持久狀態(tài)的容器奈惑。