Chrome原始碼分析之程序和執行緒模型(三)
關於Chrome的執行緒模型,在他的開發文件中有專門的介紹,原文地址在這裡:http://dev.chromium.org/developers/design-documents/threading
chrome的程序,chrome沒有采用一般應用程式的單程序多執行緒的模型,而是採用了多程序的模型,按照他的文字說明,主介面框架下的一個TAB就對應這個一個程序。但實際上,一個程序不僅僅包含一個頁面,實際上同類的頁面在共用一個程序。
chrome程序模型下有2種程序,一個是Browser程序。另一種是Renderer程序,Browser只有一個,主控整個系統的執行,而Renderer則可以有多個,主要負責頁面的渲染和顯示。
Browser作為主程序最先啟動,Browser包含一個主執行緒mainthread,在mainthread中對整個系統進行初始化,並啟動為另外幾個執行緒,看下面的程式碼:
void CreateChildThreads(BrowserProcessImpl* process) {
process->db_thread();
process->file_thread();
process->process_launcher_thread();
process->cache_thread();
process->io_thread();
}
db_thread執行緒負責資料庫處理,file_thread負責檔案管理,cache_thread負責管理快取。io_thread則負責管理程序間通訊和所有I/O行為。
這其中,io_thread不僅負責Browser程序的I/O,而且其他Renderer的I/O請求也會通過程序間通訊傳送到這個執行緒,由該執行緒進行處理,最後把結果在返回給各個Renderer程序。各個執行緒的功能不一樣,但設計模式是一樣的,下面重點分析一下io_thread的初始化和執行流程。
執行緒的建立在BrowserProcessImpl的CreateIOThread中實現,程式碼如下:
void BrowserProcessImpl::CreateIOThread() {DCHECK(!created_io_thread_ && io_thread_.get() == NULL);
created_io_thread_ = true;
PluginService::GetInstance();
#if defined(USE_X11)
// The lifetime of the BACKGROUND_X11 thread is a subset of the IO thread so
// we start it now.
scoped_ptr<base::Thread> background_x11_thread(
new BrowserProcessSubThread(BrowserThread::BACKGROUND_X11));
if (!background_x11_thread->Start())
return;
background_x11_thread_.swap(background_x11_thread);
#endif
scoped_ptr<IOThread> thread(new IOThread);
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
if (!thread->StartWithOptions(options))
return;
io_thread_.swap(thread);
}
先建立一個IOThread的例項,然後設定此執行緒的型別為TYPE_IO,接著,呼叫StartWithOptions啟動這個執行緒。
StartWithOptions函式首先是儲存傳遞進來的Options,接著通過PlatformThread::Create來建立執行緒,這裡PlatformThread類的作用是支援不同系統平臺的執行緒的建立。然後呼叫startup_data.event.Wait()來等待此執行緒的訊息迴圈的啟動,這表明只有訊息迴圈啟動之後,整個函式才能返回。
在PlatformThread::Create很簡單,呼叫系統APICreateThread,執行緒函式是ThreadFunc,傳遞給執行緒函式的引數就是IOThread物件本身的指標。
ThreadFunc也很簡單,之後呼叫Thread的成員ThreadMain, 所以ThreadMain才是執行緒的主函式。
下面詳細分析一下ThreadMain,首先定義一個MessageLoop類的物件,並把之前儲存的型別賦予這個物件。接著呼叫IOThread的Init進行基本的初始化動作,然後呼叫startup_data_->event.Signal(),讓執行緒處於未置信狀態。最後呼叫MessageLoop的Run進入無限的訊息迴圈,直到接到退出訊息迴圈的命令,此時執行緒也要結束了。這是一般windows執行緒的常用方式,只不過chrome對其進行了一定的封裝,並且把定義了幾種不同的訊息迴圈。
在MessageLoop中有一個列舉變數有如下定義:
enum Type {
TYPE_DEFAULT,
TYPE_UI,
TYPE_IO
};
可見總共有3種不同的訊息迴圈。
MessageLoopForUI::Run(Dispatcher* dispatcher);
void MessageLoop::RunHandler()