1. 程式人生 > >Chrome原始碼分析之程序和執行緒模型(三)

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()