




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、一個典型的異步通信過程如圖1所示:圖1 線程異步通信過程 Task-1被分解成三個子任務(wù)Task-1(1)、Task-1(2)和Task-1(3)。其中,Task-1(1)由Thread-1執(zhí)行。Task-1(1)執(zhí)行完成后,Thread-1通過我們在前面Chromium多線程通信的Closure機(jī)制分析一文分析的Closure請求Thread-2執(zhí)行Task-1(2)。Task-1(2)執(zhí)行完成后,Thread-2又通過一個Closure請求Thread-1執(zhí)行Task-1(3)。至此,Task-1就執(zhí)行完成。我們可以將第一個C
2、losure看作是一個Request操作,而第二個Closure是一個Reply操作。這是一個典型的異步通信過程。當(dāng)然,如果不需要知道異步通信結(jié)果,那么第二個Closure和Task-1(3)就是不需要的。 假設(shè)Thread-1需要知道異步通信的結(jié)果,那么在圖1中我們可以看到一個非常關(guān)鍵的點(diǎn):Thread-1并不是什么也不干就只是等著Thread-2執(zhí)行完成Task-1(2),它趁著這個等待的空隙,干了另外一件事情Task-2。如果我們將Thread-1看作是一個UI線程,那么就意味著這種異步通信模式是可以提高它的響應(yīng)性的。
3、160; 為了能夠完成上述的異步通信過程,一個線程的生命周期如圖2所示:圖2 線程生命周期 線程經(jīng)過短暫的啟動之后(Start),就圍繞著一個任務(wù)隊列(TaskQueue)不斷地進(jìn)行循環(huán),直到被通知停止為止(Stop)。在圍繞任務(wù)隊列循環(huán)期間,它會不斷地檢查任務(wù)隊列是否為空。如果不為空,那么就會將里面的任務(wù)(Task)取出來,并且進(jìn)行處理。這樣,一個線程如果要請求另外一個線程執(zhí)行某一個操作,那么只需要將該操作封裝成一個任務(wù),并且發(fā)送到目標(biāo)線程的任務(wù)隊列去即可。 為了
4、更好地理解這種基于任務(wù)隊列的線程運(yùn)行模式,我們腦補(bǔ)一下另外一種常用的基于鎖的線程運(yùn)行模式。一個線程要執(zhí)行某一個操作的時候,就直接調(diào)用一個代表該操作的一個函數(shù)。如果該函數(shù)需要訪問全局?jǐn)?shù)據(jù)或者共享數(shù)據(jù),那么就需要進(jìn)行加鎖,避免其它線程也正在訪問這些全局?jǐn)?shù)據(jù)或者共享數(shù)據(jù)。這樣做的一個好處是我們只需要關(guān)心問題的建模,而不需要關(guān)心問題是由誰來執(zhí)行的,只要保證邏輯正確并且數(shù)據(jù)完整即可。當(dāng)然壞處也是顯然的。首先是為了保持?jǐn)?shù)據(jù)完整性,也就是避免訪問數(shù)據(jù)時出現(xiàn)競爭條件,代碼里面充斥著各種鎖。其次,如果多個線程同時獲取同一個鎖,那么就會產(chǎn)生競爭。這種鎖競爭會帶來額外的開銷,從而降低線程的響應(yīng)性。
5、160; 基于任務(wù)隊列的線程運(yùn)行模式,要求在對問題進(jìn)行建模時,要提前知道誰是執(zhí)行者。也就是說,在對問題進(jìn)行建模時,需要指派好每一個子問題的執(zhí)行者。這樣我們?yōu)樽訂栴}設(shè)計數(shù)據(jù)結(jié)構(gòu)時,就規(guī)定這些數(shù)據(jù)結(jié)構(gòu)僅僅會被子問題的執(zhí)行者訪問。這樣執(zhí)行者在解決指派給它的問題時,就不需要進(jìn)行加鎖操作,因為在解決問題過程中需要訪問的數(shù)據(jù)不會同時被其它執(zhí)行者訪問。這就是通過任務(wù)隊列來實現(xiàn)異步通信的多線程模型的設(shè)計哲學(xué)。 當(dāng)然,這并不是說,基于任務(wù)隊列的線程運(yùn)行模式可以完全避免使用鎖,因為任務(wù)隊列本身就是一個線程間的共享資源。想象一下,一個線程
6、要往里面添加任務(wù),另一個線程要從里面將任務(wù)提取出來處理。因此,所有涉及到任務(wù)隊列訪問的地方都是需要加鎖的。但是如果我們再仔細(xì)想想,那么就會發(fā)現(xiàn),任務(wù)隊列只是一個基礎(chǔ)設(shè)施,它與具體的問題是無關(guān)的。因此,只要我們遵循上述設(shè)計哲學(xué),就可以將代碼里面需要加鎖的地方僅限于訪問任務(wù)隊列的地方,從而就可以減少鎖競爭帶來的額外的開銷。 這樣說來,似乎基于任務(wù)隊列的線程運(yùn)行模式很好,但是實際上它對問題建模提出了更高的要求,也就是進(jìn)行子問題劃分時,要求劃分出來的子問題是正交的,這樣我們才有可能為這些子問題設(shè)計出不會同時被訪問的數(shù)據(jù)結(jié)構(gòu)??吹健罢弧眱蓚€字,是不是
7、想起高數(shù)里面的向量空間的正交基了?或者傅里葉變換用到的一組三角函數(shù)了?其實道理就是一樣一樣的。 好了,說了這么多,我們就步入到正題,分析Chromium多線程模型的設(shè)計和實現(xiàn),也就是基于任務(wù)隊列的線程運(yùn)行模式涉及到核心類圖,如圖3所示:圖3 基于任務(wù)隊列的線程運(yùn)行模式核心類關(guān)系圖 Thread是一個用來創(chuàng)建帶消息循環(huán)的類。當(dāng)我們創(chuàng)建一個Thread對象后,調(diào)用它的成員函數(shù)Start或者StartWithOptions就可以啟動一個帶消息循環(huán)的線程。其中,成員函數(shù)StartWithO
8、ptions可以指定線程創(chuàng)建參數(shù)。當(dāng)我們不需要這個線程時,就可以調(diào)用之前創(chuàng)建的Thread對象的成員函數(shù)Stop。 Thread類繼承了PlatformThread:Delegate類,并且重寫了它的成員函數(shù)ThreadMain。我們知道,Chromium是跨平臺的,這樣各個平臺創(chuàng)建線程使用的API有可能是不一樣的。不過,我們可以通過PlatformThread:Delegate類為各個平臺創(chuàng)建的線程提供一個入口點(diǎn)。這個入口點(diǎn)就是PlatformThread:Delegate類的成員函數(shù)ThreadMain。由于Thread類重寫了父類Pla
9、tformThread:Delegate的成員函數(shù)ThreadMain,因此無論是哪一個平臺,當(dāng)它創(chuàng)建完成一個線程后,都會以Thread類的成員函數(shù)ThreadMain作為線程的入口點(diǎn)。 Thread類有一個重要的成員變量message_loop_,它指向的是一個MessageLoop對象。這個MessageLoop對象就是用來描述線程的消息循環(huán)的。MessageLoop類內(nèi)部通過成員變量run_loop_指向的一個RunLoop對象和成員變量pump_指向的一個MessagePump對象來描述一個線程的消息循環(huán)。
10、 一個線程在運(yùn)行的過程中,可以有若干個消息循環(huán),也就是一個消息循環(huán)可以運(yùn)行在另外一個消息循環(huán)里面。除了最外層的消息循環(huán),其余的消息的消息循環(huán)稱為嵌套消息循環(huán)。我們?yōu)槭裁葱枰短紫⒀h(huán)呢?這主要是跟模式對話框有關(guān)。 考慮一個情景,我們在一個窗口彈出一個文件選擇對話框。窗口必須要等到用戶在文件選擇對話框選擇了文件之后,才能去做其它事情。窗口是在消息循環(huán)過程中打開文件對話框的,它要等待用戶在文件選擇對話框中選擇文件 ,就意味著消息循環(huán)被中止了。由于文件選擇對話框也是通過消息循環(huán)來響應(yīng)用戶輸入的,因此如果打開的它窗口中止了消
11、息循環(huán),就會導(dǎo)致它無法響應(yīng)用戶輸入。為了解決這個問題,就要求打開文件選擇的窗口不能中止消息循環(huán)。方法就是該窗口創(chuàng)建一個子消息循環(huán),該子消息循環(huán)負(fù)責(zé)處理文件選擇對應(yīng)框的輸入事件,直到用戶選擇了一個文件為止。 MessageLoop類的成員變量run_loop_指向的一個RunLoop對象就是用來記錄線程當(dāng)使用的消息循環(huán)的。RunLoop類有三個重要的成員變量: 1. message_loop_,記錄一個RunLoop對象關(guān)聯(lián)的MessageLoop對象。 &
12、#160; 2. previous_loop_,記錄前一個消息循環(huán),當(dāng)就是包含當(dāng)前消息循環(huán)的消息循環(huán)。 3. run_depth_,記錄消息循環(huán)的嵌套深度。 MessageLoop類的成員變量pump_指向的一個MessagePump對象是用來進(jìn)行消息循環(huán)的,也就是說,Thread類描述的線程通過MessagePump類進(jìn)入到消息循環(huán)中去。 Thread類將消息劃分為三類,分別通過以下三個成員變量來描述:
13、160; 1. work_queue_,指向一個TaskQueue對象,用來保存那些需要馬上處理的消息。 2. delayed_work_queue_,指向一個DelayedTaskQueue,用來保存那些需要延遲一段時間再處理的消息。 3. deferred_non_nestable_work_queue_,指向一個TaskQueue對象,用來保存那些不能夠在嵌套消息循環(huán)中處理的消息。
14、0; 一個MessagePump對象在進(jìn)行消息循環(huán)時,如果發(fā)現(xiàn)消息隊列中有消息,那么就需要通知關(guān)聯(lián)的MessageLoop對象進(jìn)行處理。通知使用的接口就通過MessagePump:Delegate類來描述。 MessagePump:Delegate類定義了四個成員函數(shù),如下所示: 1. DoWork,用來通知MessageLoop類處理其成員變量work_queue_保存的消息。 2. DoDelayedWo
15、rk,用來通知MessageLoop類處理其成員變量delayed_work_queue_保存的消息。 3. DoIdleWork,用來通知MessageLoop類當(dāng)前無消息需要處理,MessageLoop類可以利用該間隙做一些Idle Work。 4. GetQueueingInformation,用來獲取MessageLoop類內(nèi)部維護(hù)的消息隊列的信息,例如消息隊列的大小,以及下一個延遲消息的處理時間。 有了前面的基
16、礎(chǔ)知識,接下來我們就可以大概描述Thread類描述的線程的執(zhí)行過程。 首先是線程的啟動過程: 1. 調(diào)用Thread類的成員函數(shù)Start或者StartWithOptions啟動一個線程,并且以Thread類的成員函數(shù)ThreadMain作為入口點(diǎn)。 2. Thread類的成員函數(shù)ThreadMain負(fù)責(zé)創(chuàng)建消息循環(huán),也就是通過MessageLoop類創(chuàng)建消息循環(huán)。 3.
17、0;MessageLoop類在創(chuàng)建消息循環(huán)的過程中,會通過成員函數(shù)Init創(chuàng)建用來一個用來消息循環(huán)的MessagePump對象。 4. 消息循環(huán)創(chuàng)建完成之后,調(diào)用MessageLoop類的成員函數(shù)Run進(jìn)入消息循環(huán)。 5. MessageLoop類的成員函數(shù)Run創(chuàng)建一個RunLoop對象,并且調(diào)用它的成員函數(shù)Run進(jìn)入消息循環(huán)。注意,該RunLoop對象在創(chuàng)建的過程,會關(guān)聯(lián)上當(dāng)前線程使用的消息循環(huán),也就是創(chuàng)建它的MessageLoop對象。 &
18、#160; 6. RunLoop類的成員函數(shù)Run負(fù)責(zé)建立好消息循環(huán)的嵌套關(guān)系,也就是設(shè)置好它的成員變量previous_loop_和run_depth_等,然后就會調(diào)用其關(guān)聯(lián)的MessageLoop對象的成員函數(shù)RunHandler進(jìn)入消息循環(huán)。 7. MessageLoop類的成員函數(shù)RunHandler調(diào)用成員變量pump_描述的一個MessagePump對象的成員函數(shù)Run進(jìn)入消息循環(huán)。 接下來是向線程的消息隊列發(fā)送消息的過程。這是通過MessageL
19、oop類的以下四個成員函數(shù)向消息隊列發(fā)送消息的: 1. PostTask,發(fā)送需要馬上進(jìn)行處理的并且可以在嵌套消息循環(huán)中處理的消息。 2. PostDelayedTask,發(fā)送需要延遲處理的并且可以在嵌套消息循環(huán)中處理的消息。 3. PostNonNestableTask,發(fā)送需要馬上進(jìn)行處理的并且不可以在嵌套消息循環(huán)中處理的消息。(已經(jīng)移除了) 4.
20、0;PostNonNestableDelayedTask,發(fā)送需要延遲處理的并且不可以在嵌套消息循環(huán)中處理的消息。(已經(jīng)移除了) 向線程的消息隊列發(fā)送了新的消息之后,需要喚醒線程,這是通過調(diào)用MessagePump類的成員函數(shù)Schedule進(jìn)行的。線程被喚醒之后 ,就會分別調(diào)用MessageLoop類重寫父類MessagePump:Delegate的兩個成員函數(shù)DoWork和DoDelayedWork對消息隊列的消息進(jìn)行處理。如果沒有消息可以處理,就調(diào)用MessageLoop類重寫父類MessagePump:Delegate的成員函數(shù)DoI
21、dleWork通知線程進(jìn)入Idle狀態(tài),這時候線程就可以做一些Idle Work。 MessageLoop類的成員函數(shù)DoWork在處理消息的過程中,按照以下三個類別進(jìn)行處理: 1. 對于可以馬上處理的消息,即保存在成員變量work_queue_描述的消息隊列的消息,執(zhí)行它們的成員函數(shù)Run。 2. 對于需要延遲處理的消息,將它們保存在成員變量delayed_work_queue_描述的消息隊列中,并且調(diào)用成員變量pump_指向的一個Mes
22、sagePump對象的成員函數(shù)ScheduleDelayedWork設(shè)置最早一個需要處理的延遲消息的處理時間,以便該MessagePump對象可以優(yōu)化消息循環(huán)邏輯。 3. 對于可以馬上處理但是不可以在嵌套消息循環(huán)中處理的消息,如果線程是處理嵌套消息循環(huán)中,那么將它們保存在成員變量deferred_non_nestable_work_queue_描述的消息隊列中,這些消息將會在線程進(jìn)入Idle狀態(tài)時,并且是處理最外層消息循環(huán)時,得到處理。 以上就是Thread類描述的線程的大概執(zhí)行過程,接下來
23、我們通過源碼分析詳細(xì)描述這些過程。 我們首先看線程的啟動過程,即Thread類的成員函數(shù)Start的實現(xiàn),如下所示: 1. bool Thread:Start() 2. Options options; 3. . 4. return StartWithOptions(options); 5. 這個函數(shù)定義在文
24、件external/chromium_org/base/threading/thread.cc中。Thread類的成員函數(shù)Start調(diào)用另外一個成員函數(shù)StartWithOptions來啟動一個線程,后者可以通過一個類型為Options的參數(shù)指定線程的啟動參數(shù),這里沒有指定,意味著采用默認(rèn)參數(shù)啟動一個線程。 Thread類的成員函數(shù)StartWithOptions的實現(xiàn)如下所示: 1. bool Thread:StartWithOptions(const Options& options)
25、160; 2. . 3. / Reset |id_| here to support restarting the thread.4. id_event_.Reset();5. id_ = kInvalidThreadId;6.7. SetThreadWasQuitProperly(false);8.9. MessageLoop:Type type = options.message_loop_type;10. if (!options.message_pump_factory.is_null()11. type = MessageLoo
26、p:TYPE_CUSTOM;12.13. message_loop_timer_slack_ = options.timer_slack;14. std:unique_ptr<MessageLoop> message_loop =15. MessageLoop:CreateUnbound(type, options.message_pump_factory);16. message_loop_ = message_loop.get();17. start_event_.Reset();18.19. / Hold the thread_lock_ while starting a n
27、ew thread, so that we can make sure20. / that thread_ is populated before the newly created thread accesses it.21. 22. AutoLock lock(thread_lock_);23. if (!PlatformThread:CreateWithPriority(options.stack_size, this, &thread_, options.priority) 24. DLOG(ERROR) << "failed to create thre
28、ad"25. message_loop_ = nullptr;26. return false;27. 28. 29.30. / The ownership of message_loop is managemed by the newly created thread31. / within the ThreadMain.32. ignore_result(message_loop.release(); 33. . 34. return true; 35. &
29、#160; 這個函數(shù)定義在文件external/chromium_org/base/threading/thread.cc中。變量message_loop_type來創(chuàng)建指定Message Loop的類型 ,從而確定要創(chuàng)建的MessagePump。通過調(diào)用MessageLoop:CreateUnbound來生成一個MessageLoop。start_event_是創(chuàng)建的線程使用message_loop使用的信號。1. std:unique_ptr<MessageLoop> MessageLoop:CreateUnbound(2. Type type,3.
30、MessagePumpFactoryCallback pump_factory) 4. return WrapUnique(new MessageLoop(type, pump_factory);5. 1. template <typename T>2. std:unique_ptr<T> wrapUnique(T* ptr)3. 4. return std:unique_ptr<T>(ptr);5. 通過Messageloop的構(gòu)造函數(shù)來生成。這個函數(shù)定義在文件external/chromium_org/base/message_l
31、oop/Message_loop.cc中。1. MessageLoop:MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)2. : type_(type),3. .4. nestable_tasks_allowed_(true),5. pump_factory_(pump_factory),6. message_histogram_(NULL),7. run_loop_(NULL),8. incoming_task_queue_(new internal:IncomingTaskQueue(this),9. unbou
32、nd_task_runner_(10. new internal:MessageLoopTaskRunner(incoming_task_queue_),11. task_runner_(unbound_task_runner_),12. thread_id_(kInvalidThreadId) 13. / If type is TYPE_CUSTOM non-null pump_factory must be given.14. DCHECK(type_ != TYPE_CUSTOM | !pump_factory_.is_null(); 15.
33、;MessageLoop類的成員變量type_描述的是消息循環(huán)的類型,nestable_tasks_allowed_描述當(dāng)前是否允許處理嵌套消息,runn_loop_描述的是當(dāng)前使用的消息循環(huán)。 同時創(chuàng)建了一個任務(wù)隊列,并且保存在成員變量incoming_task_queue_中。這個任務(wù)隊列通過IncomingQueue類來描述,它的定義如下所示:1. class BASE_EXPORT IncomingTaskQueue 2. : public RefCountedThr
34、eadSafe<IncomingTaskQueue> 3. public: 4. . 5. 6. bool AddToIncomingQueue(const tracked_objects:Location& from_here, 7.
35、0; const Closure& task, 8. Tim
36、eDelta delay, 9. bool nestable); 10. 11. . 12. 13.
37、160;void ReloadWorkQueue(TaskQueue* work_queue); 14. 15. . 16. 17. void WillDestroyCurrentMessageLoop(); 18. 19. . 20. 21. private: 22
38、. . 23. 24. TaskQueue incoming_queue_; 25. 26. . 27. 28. MessageLoop* message_loop_; 29. 30. . 31. ; &
39、#160; 這個類定義在external/chromium_org/base/message_loop/incoming_task_queue.h中。 IncomingQueue類有兩個重要的成員變量: 1. incoming_queue_,它描述的是一個TaskQueue,代表的是線程的消息隊列,也就是所有發(fā)送給線程的消息都保存在這里。 2. message_loop_,它指向一個MessageLoop對象,描述的是線程的消息循環(huán)。 &
40、#160; IncomingQueue類有三個重要的成員函數(shù): 1. AddToIncomingQueue,用來向成員變量incoming_queue_描述的消息隊列發(fā)送一個消息,并且喚醒線程進(jìn)行處理。 2. ReloadWorkQueue,用來提取成員變量incoming_queue_描述的消息隊列中的消息,并且保存在參數(shù)work_queue中。 3. WillDestroyCurr
41、entMessageLoop,當(dāng)該函數(shù)被調(diào)用時,會將成員變量message_loop_的值設(shè)置為NULL,使得我們不能夠再向線程發(fā)送消息,也就是請求線程執(zhí)行某一個操作。task_runner_是SingleThreadTaskRunner類型的變量,作用包括有:向現(xiàn)有的線程的MessageLoop發(fā)布任務(wù);創(chuàng)建他們自己的工作線程和 發(fā)送任務(wù)給的MessageLoop;將任務(wù)添加到一個 FIFO 和添加信號到非 MessageLoop 線程讓他們來處理。unbound_task_runner_是SingleThreadTaskRunner類型的變量,通過MessageLoop創(chuàng)建和管理的Sing
42、leThreadTaskRunner的常用實現(xiàn),只能作為MessageLoop的一部分。然后調(diào)用PlatformThread: CreateWithPriority方法。1. bool PlatformThread:CreateWithPriority(size_t stack_size, Delegate* delegate,2. PlatformThreadHandle* thread_handle,3. ThreadPriority priority) 4. return CreateThread(stack_size, true, / joinable thread5. delegat
43、e, thread_handle, priority);6. 這個函數(shù)定義在文件external/chromium_org/base/threading/PlatformThread.h中。具體的基于posix平臺的實現(xiàn)在Platform_thread_posix.cc中,調(diào)用方法CreateThread來實現(xiàn)的。下面是CreateThread函數(shù)的主要代碼。pthread_attr_init初始化一個線程對象的屬性,需要用pthread_attr_destroy函數(shù)對其去除初始化。pthread_attr_setdetachstate設(shè)置線
44、程的分離狀態(tài)。線程的分離狀態(tài)決定一個線程以什么樣的方式來終止自己。在默認(rèn)情況下線程是非分離狀態(tài)的,這種情況下,原有的線程等待創(chuàng)建的線程結(jié)束。只有當(dāng)pthread_join()函數(shù)返回時,創(chuàng)建的線程才算終止,才能釋放自己占用的系統(tǒng)資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運(yùn)行結(jié)束了,線程也就終止了,馬上釋放系統(tǒng)資源。設(shè)置線程分離狀態(tài)的函數(shù)為pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二個參數(shù)可選為PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE
45、_JOINABLE(非分離線程)。1. bool CreateThread( ) 2. DCHECK(thread_handle);3. base:InitThreading();4. . 5. pthread_attr_init(&attributes);6. . 7. if (!joinable)8. pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);9. . 10. int err = pthread_creat
46、e(&handle, &attributes, ThreadFunc, params.get();11. . 12. *thread_handle = PlatformThreadHandle(handle);13.14. pthread_attr_destroy(&attributes);15. . 16. 這個函數(shù)定義在external/chromium_org/base/threading/ Platform_thread_posix.cc中,從這里就可以看到,調(diào)用POSIX線程庫中的函數(shù)pth
47、read_create創(chuàng)建了一個線程,并且指定新創(chuàng)建的線程的入口點(diǎn)函數(shù)為ThreadFunc,同時傳遞給該入口點(diǎn)函數(shù)的參數(shù)為一個ThreadParams對象,該ThreadParams對象封裝了線程啟動過程中需要使用到的一系列參數(shù)。新創(chuàng)建線程的入口點(diǎn)函數(shù)ThreadFunc的實現(xiàn)如下所示:1. void* ThreadFunc(void* params) 2. . 3. ThreadParams* thread_params = static
48、_cast<ThreadParams*>(params); 4. 5. PlatformThread:Delegate* delegate = thread_params->delegate; 6. . 7. 8. delegate->ThreadMain(); 9. 10. .
49、; 11. return NULL; 12. 這個函數(shù)定義在external/chromium_org/base/threading/platform_thread_posix.cc中。函數(shù)ThreadFunc首先將參數(shù)params轉(zhuǎn)換為一個ThreadParams對象。有了這個ThreadParams對象之后,通過它的成員變量delegate獲得一個PlatformThread:Delegate對象。從前面的調(diào)用過程可以知道, PlatformThread:Delegate對象實際是一個Thread對象
50、,用來描述新創(chuàng)建的線程。得到了用來描述新創(chuàng)建線程的Thread對象之后,就可以調(diào)用它的成員函數(shù)ThreadMain繼續(xù)啟動線程了。 Thread類的成員函數(shù)ThreadMain的實現(xiàn)如下所示:1. void Thread:ThreadMain() 2. 3. . 4. scoped_ptr<MessageLoop>
51、; message_loop; 5. std:unique_ptr<MessageLoop> message_loop(message_loop_);6. message_loop_->BindToCurrentThread();7. message_loop_->SetTimerSlack(message_loop_timer_slack_); 8. . 9. 10.
52、60; / Let the thread do extra initialization.11. Init();12.13. 14. AutoLock lock(running_lock_);15. running_ = true;16. 17.18. start_event_.Signal();19.20. Run(message_loop_);21.22. 23. AutoLock lock(running_lock_);24. running_ = false;25. 26.27. / Let the thread do extra cleanup.28. CleanUp();
53、29.30. if (message_loop->type() != MessageLoop:TYPE_CUSTOM) 31. / Assert that MessageLoop:QuitWhenIdle was called by ThreadQuitHelper.32. / Don't check for custom message pumps, because their shutdown might not33. / allow this.34. DCHECK(GetThreadWasQuitProperly();35. 36.37. / We can't re
54、ceive messages anymore.38. / (The message loop is destructed at the end of this block)39. message_loop_ = nullptr; 40. 41. 這個函數(shù)定義在文件external/chromium_org/base/threading/thread.cc中。之前的MessageLoop已經(jīng)通過其構(gòu)造函數(shù)創(chuàng)建過。調(diào)用MessageLoop的BindToCurrentThread函數(shù),函數(shù)定義如下:1. void M
55、essageLoop:BindToCurrentThread() 2. DCHECK(!pump_);3. if (!pump_factory_.is_null()4. pump_ = pump_factory_.Run();5. else6. pump_ = CreateMessagePumpForType(type_);7.8. DCHECK(!current() << "should only have one message loop per thread"9. lazy_tls_ptr.Pointer()->Set(this);10.11. in
56、coming_task_queue_->StartScheduling();12. unbound_task_runner_->BindToCurrentThread();13. unbound_task_runner_ = nullptr;14. SetThreadTaskRunnerHandle();15. 16. / Save the current thread's ID for potential use by other threads17. / later from GetThreadName().18. thread_id_ = PlatformThread
57、:CurrentId();19. subtle:MemoryBarrier();20. 21. 該函數(shù)調(diào)用另外一個成員函數(shù)CreateMessagePumpForType根據(jù)消息循環(huán)的類型創(chuàng)建一個消息泵(Message Pump),并且保存在成員變量pump_中。MessageLoop類的成員函數(shù)CreateMessagePumpForType的實現(xiàn)如下所示:1. #if defined(USE_GLIB) && !defined(OS_NACL)2. typedef MessagePumpGlib MessagePumpForUI;3. #elif defined
58、(OS_LINUX) && !defined(OS_NACL)4. typedef MessagePumpLibevent MessagePumpForUI;5. #endif6.7. #if defined(OS_IOS) | defined(OS_MACOSX)8. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>(MessagePumpMac:Create()9. #elif defined(OS_NACL)10. / Currently NaCl doesn't have a UI Message
59、Loop.11. / TODO(abarth): Figure out if we need this.12. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>()13. #else14. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>(new MessagePumpForUI()15. #endif16.17. #if defined(OS_MACOSX)18. / Use an OS native runloop on Mac to support time
60、r coalescing.19. #define MESSAGE_PUMP_DEFAULT 20. std:unique_ptr<MessagePump>(new MessagePumpCFRunLoop()21. #else22. #define MESSAGE_PUMP_DEFAULT 23. std:unique_ptr<MessagePump>(new MessagePumpDefault()24. #endif25. . 26. if (type = MessageLoop:TYPE_
61、UI) 27. if (message_pump_for_ui_factory_) 28. return message_pump_for_ui_factory_(); 29. return MESSAGE_PUMP_UI; 30. 31.
62、 if (type = MessageLoop:TYPE_IO) 32. return scoped_ptr<MessagePump>(new MessagePumpForIO(); 33.34. #if defined(OS_ANDROID)35. if (type = MessageLoop:TYPE_JAVA)36. return std:unique_ptr<MessagePump>(ne
63、w MessagePumpForUI();37. #endif38. return scoped_ptr<MessagePump>(new MessagePumpDefault(); 39. 這個函數(shù)定義在文件external/chromium_org/base/message_loop/message_loop.cc中。上面的代碼通過一系列宏來適配不同的平臺,這里我們只考慮Linux平臺,這意味著MessagePumpForUI定義為MessagePumpLibevent,MES
64、SAGE_PUMP_UI定義為std:unique_ptr<MessagePump>(new MessagePumpForUI()。MESSAGE_PUMP_DEFAULT定義為std:unique_ptr<MessagePump>(new MessagePumpDefault()。 從MessageLoop類的成員函數(shù)CreateMessagePumpForType的實現(xiàn)可以知道: 1. 如果消息循環(huán)的類型為MessageLoop:TYPE_UI,那么對應(yīng)的消息泵為
65、MessagePumpForUI,或者由函數(shù)指針message_pump_for_ui_factory_指向的函數(shù)創(chuàng)建。但是一般不設(shè)置函數(shù)指針message_pump_for_ui_factory_,因此,類型為MessageLoop:TYPE_UI的消息循環(huán)對應(yīng)的消息泵為MessagePumpForUI。在Chromium中,消息循環(huán)類型為MessageLoop:TYPE_UI的線程稱為UI線程,也就是應(yīng)用程序的主線程。 2. 如果消息循環(huán)的類型為MessageLoop:TYPE_IO,那么對應(yīng)的消息泵為MessagePumpFo
66、rIO,即MessagePumpLibevent。在Chromium中,消息循環(huán)類型為MessageLoop:TYPE_IO的線程稱為IO線程,但是這里的IO不是讀寫文件的意思,而是執(zhí)行IPC的意思。 3. 如果消息循環(huán)的類型為MessageLoop:TYPE_JAVA,那么對應(yīng)的消息泵為MessagePumpForUI。在Chromium中,消息循環(huán)類型為MessageLoop:TYPE_JAVA的線程稱為JAVA線程,它們與UI線程一樣,在JAVA層具有自己的消息循環(huán)。 4. 其余類型的
67、消息循環(huán),對應(yīng)的消息泵為MessagePumpDefault。 總結(jié)來說,就是在Linux平臺上,涉及到的消息泵有MessagePumpForUI、MessagePumpForIO和MessagePumpDefault三種,各自有不同的用途,其中MessagePumpForUI適用于具有自己的消息循環(huán)的UI線程,MessagePumpLibevent適用于用來負(fù)責(zé)執(zhí)行IPC的IO線程,MessagePumpDefault適用于其它的一般線程。我們先從一般性出發(fā),分析MessagePumpDefault的實現(xiàn),后面再分析MessagePumpF
68、orUI和MessagePumpForIO的實現(xiàn)。 MessagePumpDefault類繼承于MessagePump類,它的定義如下所示:1. class MessagePumpDefault : public MessagePump 2. public: 3. MessagePumpDefault(); 4. virtual MessagePumpDef
69、ault(); 5. 6. / MessagePump methods: 7. virtual void Run(Delegate* delegate) OVERRIDE; 8. virtual void Quit() OVERRIDE; 9. virtual void ScheduleWork() OVERRIDE; 10. virtual void ScheduleDelayedWork(cons
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 香椿種植轉(zhuǎn)讓合同范本
- 南昌購房合同范本
- 余泥外運(yùn)合同范本
- 衛(wèi)星定位合同范本
- 合同范本從里
- 不良資產(chǎn)合同范本
- 小型裝修合同范本
- 北京地暖合同范本
- 包工頭和工人簽合同范本
- 合同范本快速打字
- 日本商務(wù)禮儀課件
- 公務(wù)用車申請表
- 中國民間傳說:田螺姑娘
- 淺談鋼琴即興伴奏在教學(xué)中應(yīng)用現(xiàn)狀及提高方法 論文
- 身體功能訓(xùn)練
- 部編人教版四年級語文下冊《全冊全套》課件ppt
- 英文版-你來比劃我來猜游戲
- 皖2015s209 混凝土砌塊式排水檢查井
- 五年級道德與法治下冊 (我參與我奉獻(xiàn))新課件
- 診所負(fù)責(zé)人聘用合同
- 單層工業(yè)廠房排架結(jié)構(gòu)設(shè)計正文
評論
0/150
提交評論