Chormium线程模型及应用指南

原创 2016年01月09日 01:12:54

核心概念

设计上遵循以下原则:

1 不要在UI线程做任何阻塞式的I/O操作,以及其它耗时的操作,通过消息传递把各种操作传给相应用途的线程去做。

2 不鼓励线程加锁机制和线程安全对象。对象只存在一个线程,通过消息来实现线程之间的通信,线程之间不互相阻塞。通过callback对象实现跨线程请求。

一般情况下,我们应该利用一个现有的线程,尽量不要创建新的线程。UI线程实际上会被设置为不允许I/O操作,并且不允许等待。 


线程列表

核心线程列表

所属进程线程名称类型职责实现
 BrowserUI / BrowserThreadJavaBrowser的主线程content::BrowserThreadImpl
 Browser Chrome_DBThreadNative负责数据库(SQLite)相关的操作,很多功能的实现会用到该线程。content::BrowserThreadImpl
 Browser Chrome_FileThreadNative文件的创建、删除、读写等。content::BrowserThreadImpl
 Browser Chrome_FileUserBlockingThreadNative用于读取与用户交互有关的数据,需要快速的响应。看到net log模块和appcache有用。content::BrowserThreadImpl
 Browser Chrome_ProcessLauncherThreadNative用于启动和终止子进程。content::BrowserThreadImpl
 Browser Chrome_CacheThreadNative  
    content::BrowserThreadImpl
 Browser IndexedDBNativeIndexDB存储线程。base::Thread
GPU Chrome_InProcGpuThreadNativeGPU的单进程版本实现。content::InProcessGpuThread
Child ProcessesChrome_ChildIOThreadNative子进程的IO线程实现。base::Thread
RendererChrome_InProcRendererThreadNativeRenderer进程的单进程版本实现。content::InProcessRendererThread

 

其它线程

线程名称Module实现说明
CookieMonsterClientCAWbase::Thread 
CookieMonsterBackendCAWbase::Thread 
CookieSyncManagerWebViewRunnable 
Chrome_libJingle_WorkerThreadBrowserbase::Thread 
Blink Heap Marker Thread (*)Blinkbase::Thread 
Blink GC Sweeper (*)Blinkbase::Thread 
HTMLParserThreadBlinkbase::Thread 
AsyncTransferThreadgpugpu::TransferThread 
BrowserBlocking WorkerBrowserbase::SequencedWorkerPool详见:Chromium中应用C/C++并发技术要点
SimpleCache Workernetbase::SequencedWorkerPool 
Network File Threadnetbase::Thread 

  

线程结构

(以单进程模型说明)

Android下线程的消息结构


Chromium的线程结构


各个类的职责说明:

职责说明
RunLoop

一个辅助类,主要封装消息循环 MessageLoop 类,其本
身没有特别的功能,主要提供一组公共接口被调用,其实质是调用 MessageLoop 类的接口和实现

MessageLoop

主消息循环,原理上讲,它应该可以处理三种类型的消息,包括支持不同平台的消息。

事实上,如果让它处理所有这些消息,这会让其代码结构复杂不清难以理解。消息循环只需要三种类型:

  • 一种仅能处理自定义任务
  • 一种能处理自定义任务和 IO 操作
  • 一种是能处理自定义任务和 UI 消息。


很自然地,Chromium 定义一个基类 MessageLoop 用于处理自定义任务,两个子类对应于第二和第三种类型。

对于第二和第三种 MessageLoop 类型,它们除了要处理任务外,还要处理平台相关的消息,为了结构清晰,
chromium 定义一个新的基类及其子类来负责处理它们,这就是 MessagePump。MessagePump 的每个子类针对不同平台
和不同的消息类型。

MessagePump

一个抽象出来的基类,可以用来处理上面所列的第二和第三种消息类型。对于每个平台,它们有不同的
MessagePump 的子类来对应,这些子类被包含在 MessageLoopForUI 和 MessageLoopForIO 类中。

摘自:<<理解WebKit和Chromium>> 


Browser端线程结构



Browser端抛转线程消息,主要是基于BrowserThread提供的方法来完成的,如下:

// 检测所在的线程
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
// 抛转任务到UI线程执行
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
        base::Bind(&AwLoginDelegate::HandleHttpAuthRequestOnUIThread,
                   this, (count->auth_attempts_ == 0)));
 
// 抛转任务到IO线程
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
      base::Bind(&AwLoginDelegate::ProceedOnIOThread,
                 this, user, password));

 

 

Render端的线程结构 



Renderer端抛转消息,主要是基于MessageLoopProxy来完成。如下:

base::Closure closure =
        base::Bind(&CompositorOutputSurface::ShortcutSwapAck,
                   weak_ptrs_.GetWeakPtr(),
                   output_surface_id_,
                   base::Passed(&frame->gl_frame_data),
                   base::Passed(&frame->software_frame_data));
base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure);
 
// input_event_filter.cc中的示例
io_loop_->PostTask(FROM_HERE,
                     base::Bind(&InputEventFilter::SendMessageOnIOThread,
                                this,
                                base::Passed(&message)));
 
// Blink platform implemetation
base::MessageLoopProxy::current()->PostTask(
      FROM_HERE,
      base::Bind(&PlatformEventObserverBase::SendFakeDataForTesting,
                 base::Unretained(observer), data));

 

gpu与Browser/Renderer的交互




线程安全

对于Java及Android的线程安全不再展开,可以参考附件的资料:<<Efficient Android Threading Asynchronous Processing Techniques for Android Applications>>

关于Java则推荐《Java并发实战》。

最常用的形式,将使用的对象定义为base::RefCountedThreadSafe。保证引用的对象不会被提前析构。

对于一些非线程安全的类可以使用NonThreadSafe提供Debug模式下线程安全确认。也可以应用ThreadCollisionWarner/ThreadChecker 确保运行线程与设计一致。

详见:Chromium中应用C/C++并发技术要点

参考: 如何安全的使用PostTask


任务的取消

除了任务按需要取消外,如果在宿主类析构后执行就可能导致崩溃。目前使用两种方式保证任务的取消:

    WeakPtrFactory (WeakPtr)和CancelableTaskTracker, 它们析构时也会自动将任务取消。

CancelableTaskTracker可以参考Chromium官网的说明或是在FaviconCache中的应用。

class UserInputHandler : public base::RefCountedThreadSafe<UserInputHandler> {
  // Runs on UI thread.
  void OnUserInput(Input input) {
    CancelPreviousTask();
    DBResult* result = new DBResult();
    task_id_ = tracker_->PostTaskAndReply(
        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(),
        FROM_HERE,
        base::Bind(&LookupHistoryOnDBThread, this, input, result),
        base::Bind(&ShowHistoryOnUIThread, this, base::Owned(result)));
  }
 
  void CancelPreviousTask() {
    tracker_->TryCancel(task_id_);
  }
 
  ...
 
 private:
  CancelableTaskTracker tracker_;  // Cancels all pending tasks while destruction.
  CancelableTaskTracker::TaskId task_id_;
  ...
};

 

对于WeakPtr,Chromium已经封装了一个WeakptrFactory供使用。可以参考GpuBrowserCompositorOutputSurface中的使用。使用方式比较简单,但没有CancelableTaskTracker通用。

下面是一个简单的示例(使用WeakPtrFactory<>最大的好处是不用修改类的定义.)

class MyObject {
 public:
  MyObject() : weak_factory_(this) {}
 
  void DoSomething() {
    const int kDelayMS = 100;
    MessageLoop::current()->PostDelayedTask(FROM_HERE,
        base::Bind(&MyObject::DoSomethingLater, weak_factory_.GetWeakPtr()),
        kDelayMS);
  }
 
  void DoSomethingLater() {
    ...
  }
 
 private:
  base::WeakPtrFactory<MyObject> weak_factory_;
};
*非线程安全,可以跨线程传递,但必须在一个线程上使用这个WeakPtr,即只能在运行在相同线程的任务上使用这个机制。
*类中WeakPtrFactory<Foo> weak_factory_的成员需要放在所有其他成员的后面,确保其他成员的析构函数执行的时候WeakPtrs还是无效的。

  

关于WeakPtr的进一步解释可以参考: Chromium中的weak_ptr,以及 关于SupportWeakPtr与WeakPtrFactory的选择


相关文章推荐

[Chromium]如何安全的使用PostTask

一般场景决策树如何传递绑定的对象官方的解释总是最权威,有疑问看这里或者直接看代码中的说明: bind_helpers.h. 传值方式描述示例this 或 对象指针如果对象本身是一个RefCounted...

Chrom 的线程模型

线程(http://www.chromium.org/developers/design-documents/threading ) a) 概述 Chromium是一个超级多线程的产品,我们尝试让...
  • dylgsy
  • dylgsy
  • 2012年08月08日 21:43
  • 4755

WebKit之Chromium的Render进程分析

配置多进程的情况下,Chromium的网页渲染和JS执行在一个单独的进程中进行。这个进程称为Render进程,由Browser进程启动。在Android平台中,Browser进程就是Android应用...
  • sauphy
  • sauphy
  • 2016年01月13日 00:22
  • 1107

Chrome多线程模型的优缺点

开源是口好东西,它让这个充斥着大量工业垃圾代码和教材玩具代码的行业,多了一些艺术气息和美的潜质。它使得每个人,无论你来自米国纽约还是中国铁岭,都有机会站在巨人的肩膀上,如果不能,至少也可以抱一把大腿。...

Chromium多进程,多线程剖析

Chromium多进程的原因: 1. 提高浏览器的健壮性:包括单个plugin,单个页面的崩溃导致整个浏览器的崩溃; 2. 提高浏览器的安全性:基于多进程的安全模型(sanbox模型),比如Rende...

Android属性动画深入分析:让你成为动画牛人

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17841165 前言 感谢你阅读本文,我坚信读完本文肯定不会让你失望的。想要做...

手把手教你构建 Android WebView 的缓存机制 & 资源预加载方案

前言 由于H5具备 开发周期短、灵活性好 的特点,所以现在 Android App大多嵌入了 Android Webview 组件进行 Hybrid 开发 但我知道你一定在烦恼 Android Web...

Android应用程序线程消息循环模型分析

http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是通过消息来驱动的,即在应用程序的...

Android应用程序线程消息循环模型分析

我们知道,Android应用程序是通过消息来驱动的,即在应用程序的主线程(UI线程)中有一个消息循环,负责处理消息队列中的消息。我们也知道,Android应用程序是支持多线程的,即可以创建子线程来执行...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Chormium线程模型及应用指南
举报原因:
原因补充:

(最多只允许输入30个字)