核心概念
设计上遵循以下原则:
1 不要在UI线程做任何阻塞式的I/O操作,以及其它耗时的操作,通过消息传递把各种操作传给相应用途的线程去做。
2 不鼓励线程加锁机制和线程安全对象。对象只存在一个线程,通过消息来实现线程之间的通信,线程之间不互相阻塞。通过callback对象实现跨线程请求。
一般情况下,我们应该利用一个现有的线程,尽量不要创建新的线程。UI线程实际上会被设置为不允许I/O操作,并且不允许等待。
线程列表
核心线程列表
所属进程 | 线程名称 | 类型 | 职责 | 实现 |
---|---|---|---|---|
Browser | UI / BrowserThread | Java | Browser的主线程 | content::BrowserThreadImpl |
Browser | Chrome_DBThread | Native | 负责数据库(SQLite)相关的操作,很多功能的实现会用到该线程。 | content::BrowserThreadImpl |
Browser | Chrome_FileThread | Native | 文件的创建、删除、读写等。 | content::BrowserThreadImpl |
Browser | Chrome_FileUserBlockingThread | Native | 用于读取与用户交互有关的数据,需要快速的响应。看到net log模块和appcache有用。 | content::BrowserThreadImpl |
Browser | Chrome_ProcessLauncherThread | Native | 用于启动和终止子进程。 | content::BrowserThreadImpl |
Browser | Chrome_CacheThread | Native | ||
content::BrowserThreadImpl | ||||
Browser | IndexedDB | Native | IndexDB存储线程。 | base::Thread |
GPU | Chrome_InProcGpuThread | Native | GPU的单进程版本实现。 | content::InProcessGpuThread |
Child Processes | Chrome_ChildIOThread | Native | 子进程的IO线程实现。 | base::Thread |
Renderer | Chrome_InProcRendererThread | Native | Renderer进程的单进程版本实现。 | content::InProcessRendererThread |
其它线程
线程名称 | Module | 实现 | 说明 |
---|---|---|---|
CookieMonsterClient | CAW | base::Thread | |
CookieMonsterBackend | CAW | base::Thread | |
CookieSyncManager | WebView | Runnable | |
Chrome_libJingle_WorkerThread | Browser | base::Thread | |
Blink Heap Marker Thread (*) | Blink | base::Thread | |
Blink GC Sweeper (*) | Blink | base::Thread | |
HTMLParserThread | Blink | base::Thread | |
AsyncTransferThread | gpu | gpu::TransferThread | |
BrowserBlocking Worker | Browser | base::SequencedWorkerPool | 详见:Chromium中应用C/C++并发技术要点 |
SimpleCache Worker | net | base::SequencedWorkerPool | |
Network File Thread | net | base::Thread |
线程结构
(以单进程模型说明)
Android下线程的消息结构
Chromium的线程结构
各个类的职责说明:
类 | 职责说明 |
---|---|
RunLoop | 一个辅助类,主要封装消息循环 MessageLoop 类,其本 |
MessageLoop | 主消息循环,原理上讲,它应该可以处理三种类型的消息,包括支持不同平台的消息。 事实上,如果让它处理所有这些消息,这会让其代码结构复杂不清难以理解。消息循环只需要三种类型:
对于第二和第三种 MessageLoop 类型,它们除了要处理任务外,还要处理平台相关的消息,为了结构清晰, |
MessagePump | 一个抽象出来的基类,可以用来处理上面所列的第二和第三种消息类型。对于每个平台,它们有不同的 |
摘自:<<理解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 确保运行线程与设计一致。
参考: 如何安全的使用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的选择 .