Chormium线程模型及应用指南
核心概念
设计上遵循以下原则:
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 |
主消息循环,原理上讲,它应该能够处理三种类型的消息,包括支持不同平台的消息。 其实,假设让它处理全部这些消息,这会让其代码结构复杂不清难以理解。 消息循环仅仅须要三种类型:
非常自然地,Chromium 定义一个基类 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 implemetationbase::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的选择.
Chormium线程模型及应用指南的更多相关文章
- Netty IO线程模型学习总结
Netty框架的 主要线程是IO线程.线程模型的好坏直接决定了系统的吞吐量.并发性和安全性. Netty的线程模型遵循了Reactor的基础线程模型.以下我们先一起看下该模型 Reactor线程模型 ...
- Netty 基本组件与线程模型
Netty 的学习内容主要是围绕 TCP 和 Java NIO 这两个点展开的,由于 Netty 是基于 Java NIO 的 API 之上构建的网络通讯框架,Java NIO 中的几个组件,都能在 ...
- Netty系列之Netty线程模型
Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...
- Dubbo入门到精通学习笔记(十一):Dubbo服务启动依赖检查、Dubbo负载均衡策略、Dubbo线程模型(结合Linux线程数限制配置的实战分享)
文章目录 Dubbo服务启动依赖检查 Dubbo负载均衡策略 Dubbo线程模型(结合Linux线程数限制配置的实战分享) 实战经验分享( ** 属用性能调优**): Dubbo服务启动依赖检查 Du ...
- 看我是如何处理自定义线程模型---java
看过我之前文章的园友可能知道我是做游戏开发,我的很多思路和出发点是按照游戏思路来处理的,所以和web的话可能会有冲突,不相符合. 来说说为啥我要自定义线程模型呢? 按照我做的mmorpg或者mmoar ...
- HBase的Write Ahead Log (WAL) —— 整体架构、线程模型
解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...
- Netty学习三:线程模型
1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...
- Mina、Netty、Twisted一起学(十):线程模型
要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...
- WPF QuickStart系列之线程模型(Thread Model)
这篇博客将介绍WPF中的线程模型. 首先我们先来看一个例子,用来计算一定范围内的素数个数. XAML: <Grid> <Grid.RowDefinitions> <Row ...
随机推荐
- python之禅---对象与元类
众所周知,python是一门面向对象的编程语言,python中一切皆对象,那么我们先探讨一下什么是对象. 一.对象 在生活中一个事物就是一个对象,比如:一只猫就是一个对象,猫的体型.猫毛的颜色等是它的 ...
- unity 自动删除未引用的Assets下的资源
随着时间的堆积,项目中Assets文件夹下的资源会变得越来越繁杂,有些贴图.材质啥的可能压根没有使用过,但是又不敢轻易去删除. 这里分享两个插件,用于管理这些资源. 一.ResourceChecker ...
- SCU 1095运送物资(最短路)
SCU 1095运送物资(最短路) X国发生了内战.起义军得到了广大人民的支持.在一次战役中,反动军队结集了大量兵力,围攻起义军的主堡W城.为支援前线,后方各个供给基地城市纷纷准备将物资运往W城.各基 ...
- Android入门篇(一)Androidproject的搭建,导入与导出,图标的改动
先说一些题外话吧.这是小珂同学的处女作.可能写的不好,请各位读者见谅.我先讲讲我为什么要写博文,那应该也是机缘巧合,有一次.我问学长一个问题,学长发了一个连接给我,里面是一篇博客.那时我仅仅是看 ...
- Gym - 100625G Getting Through 计算几何+并查集
http://codeforces.com/gym/100625/attachments/download/3213/2013-benelux-algorithm-programming-contes ...
- 用Linux建立多应用系统备份服务器
用Linux建立多应用系统备份服务器 本文旨在结合自己的工作实际,利用LinuxFTP服务器建立了一个多系统备份服务器异地备份策略. 1 建立LinuxFTP服务器 使用了Red Hat Enterp ...
- .net开源CMS
提起开源cms,大家第一想到的是php的cms,因为php开源的最早,也最为用户和站长们认可,随着各大cms系统的功能的不断完善和各式各样的开源cms的出现,.net和java的高端的cms系统也逐渐 ...
- Python正则表达式初识(八)
继续分享Python正则表达式的基础知识,今天给大家分享的特殊字符是“\w”和“\W”,具体的教程如下. 1.“\w”代表的意思是该字符为任意字符,但是和特殊字符“.”的意思不同.“\w”代表的字符主 ...
- 现实人脸识别性别之路----弄清楚train_test_split函数
'''train_test_split(trian_data,trian_target,test_size,random_state)各个参数表示的意义:trian_data表示被划分的样本特征集tr ...
- 学习NLP:《精通Python自然语言处理》中文PDF+英文PDF+代码
自然语言处理是计算语言学和人工智能之中与人机交互相关的领域之一. 推荐学习自然语言处理的一本综合学习指南<精通Python自然语言处理>,介绍了如何用Python实现各种NLP任务,以帮助 ...