网上已经有网友duguguiyu针对Chrome的线程体系做了很专业的描述了,应该说从原理上已经很完整了。本文主要在网友的基础上从代码实现的角度上进行一些补充和分析。
提到线程,我想大家关注的无非几点:线程的消息循环机制、多线程同步机制,线程间通信机制。
本文也是从大家关注的几点来重点描述。
在Chrome的代码中,与线程相关的文件主要在\base\base.vcproj中。
主要包含了以下相关文件:
task.h 线程执行的任何任务都是以task对象方式传递,有不同类型的task。
message_pump.h
message_pump_default.h
message_pump_default.cc
message_pump_win.h
message_pump_win.cc 消息泵类,消息调度,分发处理。
message_loop.h
message_loop.cc 消息循环机制,基本上每一个线程都有自己的消息循环,接收来自其他线程、UI甚至系统的消息。
thread.h
thread.cc 线程虚类类。Thread类在操作系统上层做了抽象,本身与平台无关
platform_thread.h
platform_thread_win.cc Windows平台下线程的相关方法。在Windows平台下是CreateThread方法。
thread_local.h
thread_local.cc
thread_local_storage.h
thread_local_storage_win.cc 线程本地存储机制的实现(TLS)
其他还有一些辅助类,可以不用太关注,比如智能指针、一些简单的工具类等。我们重点分析上述的代码。
总体来说,Chrome的线程实现,主要运用了Command、Bridge和Observer三种模式。
线程类(Thread)的结构和简单流程
我们观看一下Thread.h中对Thread的定义
- //线程的抽象类
- // PlatformThread是底层的线程辅助类,实现不同平台下的真正的线程实现。
- // PlatformThread: Delegate,代理接口类,包含了ThreadMain函数。
- //由Thread的子类实现,执行由PlatformThread传递到线程的回调函数中
- classThread : PlatformThread::Delegate {
- public:
- structOptions {
- //线程消息循环类型有三种,Default(普通的后台线程),UI,IO线程
- //不同线程消息循环处理消息的方式有一些差异。
- MessageLoop::Type message_loop_type;
- //制定线程堆栈大小
- size_t stack_size;
- Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
- Options(MessageLoop::Type type, size_t size)
- : message_loop_type(type), stack_size(size) {}
- };
- explicitThread(constchar*name);
- virtual~Thread();
- boolStart();
- boolStartWithOptions(constOptions&
options);
- voidStop();
- voidStopSoon();
- //获取消息循环实例,每一个线程的核心消息循环所在
- MessageLoop* message_loop()const{returnmessage_loop_;
}
- conststd::string &thread_name() {returnname_;
}
- PlatformThreadHandle thread_handle() {returnthread_;
}
- PlatformThreadId thread_id()const{returnthread_id_;
}
- boolIsRunning()const{returnthread_id_
!= 0; }
- protected:
- virtualvoidInit()
{}
- virtualvoidCleanUp()
{}
- staticvoidSetThreadWasQuitProperly(boolflag);
- staticboolGetThreadWasQuitProperly();
- private:
- //实现了Platform_Thread类的Delegate接口
- virtualvoidThreadMain();
- boolthread_was_started()const{returnstartup_data_
!= NULL; }
- structStartupData;
- StartupData* startup_data_;
- PlatformThreadHandle thread_;
- MessageLoop* message_loop_;
- PlatformThreadId thread_id_;
- // The name of the thread. Used for debugging purposes.
- std::string name_;
- friendclassThreadQuitTask;
- DISALLOW_COPY_AND_ASSIGN(Thread);
- };
//平台相关的线程函数,不同平台有不同的实现机制。
classPlatformThread {
- public:
- staticPlatformThreadId CurrentId();
- staticvoidYieldCurrentThread();
- staticvoidSleep(intduration_ms);
- staticvoidSetName(constchar*
name);
- classDelegate {
- public:
- virtual~Delegate() {}
- virtualvoidThreadMain()
= 0;
- };
- staticboolCreate(size_t
stack_size, Delegate*delegate,
- PlatformThreadHandle* thread_handle);
- staticboolCreateNonJoinable(size_t
stack_size, Delegate*delegate);
- staticvoidJoin(PlatformThreadHandle
thread_handle);
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
- };
Thread是一个与平台无关的线程抽象类。真正线程创建的相关函数在PlatformThread类中处理,而PlatformThread类的实现根据不同的操作系统又有不同的实现。在Windows平台下实现的是
platform_thread_win.cc。
我们跟踪一下线程函数的执行流程:
下面是platform_thread_win.cc中的实现:
- DWORD__stdcallThreadFunc(void*
closure) {
- PlatformThread::Delegate*delegate=
- static_cast<PlatformThread::Delegate*>(closure);
- delegate->ThreadMain();
- returnNULL;
- }
- boolPlatformThread::Create(size_t stack_size, Delegate*delegate,
- PlatformThreadHandle* thread_handle) {
- unsignedintflags
= 0;
- if(stack_size > 0 && win_util::GetWinVersion()
>= win_util::WINVERSION_XP) {
- flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
- }else{
- stack_size = 0;
- }
- *thread_handle = CreateThread(
- NULL, stack_size, ThreadFunc,delegate,
flags, NULL);
- return*thread_handle != NULL;
- }
1.*thread_handle = CreateThread(
NULL, stack_size, ThreadFunc,delegate,
flags, NULL);
ThreadFunc是线程函数,线程的执行体从此开始。
2. ThreadFunc函数实际调用的是delegate->ThreadMain();函数,由于Thread类实现了PlatformThread:Delegate代理类,
因此实际上调用的是Thread类的ThreadMain函数。
3.观察Thread类的ThreadMain函数实现,ThreadMain函数实际启动了消息循环MessageLoop,MessageLoop类接收不同的任务,并进行处理。
voidThread::ThreadMain() {
//创建消息循环.
MessageLoop message_loop(startup_data_->options.message_loop_type);
thread_id_ = PlatformThread::CurrentId();
PlatformThread::SetName(name_.c_str());
message_loop.set_thread_name(name_);
message_loop_ = &message_loop;
//进一步初始化
Init();
//设置启动完毕信号量信号
startup_data_->event.Signal();
//消息循环开始启动,线程阻塞于此
message_loop.Run();
//线程结束,收尾工作
CleanUp();
DCHECK(GetThreadWasQuitProperly());
message_loop_ = NULL;
thread_id_ = 0;
}
4.我们进一步跟踪一下MessageLoop的Run函数实现。可以发现实际上真正的线程调度工作是MessagePump类来实现的。
-
voidMessageLoop::Run() {
-
AutoRunState save_state(this);
- RunHandler();
- }
-
voidMessageLoop::RunHandler() {
-
#ifdefined(OS_WIN)
-
if(exception_restoration_)
{
- LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
-
__try{
- RunInternal();
-
}__except(SEHFilter(current_filter))
{
- }
-
return;
- }
- #endif
- RunInternal();
- }
-
voidMessageLoop::RunInternal() {
-
DCHECK(this==
current());
- StartHistogrammer();
-
#ifdefined(OS_WIN)
-
//暂时我们可以过滤掉这个分支
-
if(state_->dispatcher)
{
-
pump_win()->RunWithDispatcher(this,
state_->dispatcher);
-
return;
- }
- #endif
-
pump_->Run(this);
- }
5.由于MessagePump类是一个虚类,其根据不同的线程类型有不同的调度方法,我们先看看MessagePumpDefault类怎么实现的。
voidMessagePumpDefault::Run(Delegate*delegate)
{
DCHECK(keep_running_) <<"Quit must have
been called outside of Run!";
for(;;)
{
ScopedNSAutoreleasePool autorelease_pool;
booldid_work
=delegate->DoWork();
if(!keep_running_)
break;
did_work |=delegate->DoDelayedWork(&delayed_work_time_);
if(!keep_running_)
break;
if(did_work)
continue;
did_work =delegate->DoIdleWork();
if(!keep_running_)
break;
if(did_work)
continue;
if(delayed_work_time_.is_null())
{
event_.Wait();
}else{
TimeDelta delay = delayed_work_time_ - Time::Now();
if(delay
> TimeDelta()) {
event_.TimedWait(delay);
}else{
// It looks like delayed_work_time_
indicates a time in the past, so we
// need to call DoDelayedWork now.
delayed_work_time_ = Time();
}
}
// Since event_ is auto-reset, we don't
need to do anything special here
// other than service each delegate method.
}
keep_running_ =true;
}
这个函数实现了任务的调度算法,真正的工作又其实是MessageLoop类实现的(MessageLoop类实现了MessagePump:Delegate类)。
MessageLoop类包含了多个任务队列(即时执行任务,延时执行任务,Idle任务),并提供接口用户提交任务,
这个函数的实现有一些灵巧的调度算法包含在里面,我们将在第二节的消息循环中去详细讲解。
从上面的分析来看,Thread类并不真正的实现任何业务功能,仅仅实现了任务的调度,线程的启动、停止等功能,线程需要执行的工作都是由用户来提交的。这个任务就是Task类的提交的,这里用到了典型的Command模式。
线程实现中的一些模式
下面的图是设计模式中Command模式的典型结构图:
引用《设计模式》中的话:
把一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
引用网友Venus的话。
Command模式
Command 模式,是一种看上去很酷的模式,传统的面向对象编程,我们封装的往往都是数据,在Command模式下,我们希望封装的是行为。这件事在函数式编程中很正 常,封装一个函数作为参数,传来传去,稀疏平常的事儿;但在面向对象的编程中,我们需要通过继承、模板、函数指针等手法,才能将其实现。。。
应用Command模式,我们是期望这个行为能到一个不同于它出生的环境中去执行,简而言之,这是一种想生不想养的行为。我们做Undo/Redo的时 候,会把在任一一个环境中创建的Command,放到一个队列环境中去,供统一的调度;在Chrome中,也是如此,我们在一个线程环境中创建了 Task,却把它放到别的线程中去执行,这种寄居蟹似的生活方式,在很多场合都是有用武之地的。。。
对应在Chrome中线程的实现Task实现了Command模式中的Command接口,而类似CancelableTask,DeleteTask,ReleaseTask等类实现了COncreteCommand类。MessageLoop类相当于是一个Receiver,负责接收各种任务,并进行处理。
举一个例子:
这种设计方法,把线程的调度和实际的任务进行了分离,减少了模块之间的耦合性。同时具有:
1. 与我们传统的实现方式不同,抛弃了Callback函数方式,先注册,以后调用。采用Task方式,具有更多的自由度。
2. 一个Task对象和原先的请求发出者(Invoker)可以有不同的生命期。换言之,原先的请求发出者(Invoker)可能已经不在了,而Task对象本身仍然是活动的。
分享到:
相关推荐
Chrome multi-threaded download manager extension,based on Aria2 and AriaNg... Chrome多线程下载扩展。.zip,Chrome multi-threaded download manager extension,based on Aria2 and AriaNg. Chrome多线程下载扩展。
phantomjs.exe,chromedriver.exe文件改个名字 填上绝对路径 就可以打开多个浏览器对象 .包含 phantomjs.exe,chromedriver.exe 和示例
chrome chrome
chrome chrome chrome chrome
chrome插件XSwitch chrome插件XSwitch
Google Chrome Backup 是一款完整备份Chrome设置(包括历史和扩展), Chrome 历史记录、书签、扩展等等信息的工具,支持 Chromium 及 Portable 版本。 如果使用的是安装版的 Chrome,那么运行 Google Chrome Backup...
Axure RP Chrome 0.6.4 原型工具Chrome扩展插件,支持最新版本Chrome浏览器,安装方法如下(亲测可用): 1、打开谷歌浏览器,在浏览器中地址栏中输入chrome://extensions/,或者点击浏览器的右上角选择更多工具,...
autoit控制chrome的扩展库,正式拜托麻烦的IE
在国内使用Chrome浏览器的小伙伴,一直都比较愁。Chrome数据同步的问题。原因大家都懂。 有什么好办法来同步Chrome的数据呢?这里给大家推荐一个Chrome扩展。 官方网站 ...
·包含V8 Javascript虚拟机,这个多线程的虚拟机可以加速Javascript的执行。 ·具备隐私模式,可以让用户无需在本地机器上登录即可使用,这个功能与微软IE8中的Incognito类似。 ·浏览器将内置防止“网络钓鱼...
(1)vue 2.x 调试工具:vue_devtools_chrome_5.3.4.crx Chrome浏览器Vue调试插件; (2)直接安装使用无需自己编译; (3)安装方法:打开Chrome浏览器,输入“chrome://extensions/”打开扩展程序,启用开发者模式...
谷歌浏览器 Chrome 安装包 ChromeSetup.exe
Axure RP Extension for Chrome是原型设计工具Axure RP的Chrome浏览器插件。因为在线安装需要访问Google Chrome在线商店,访问不了。所以提供一个离线版本进行安装。 安装方法: 1、打开Chrome浏览器,找到“工具 ->...
ChromeSetup+Chrome安装软件
Chrome浏览器插件axure-chrome-extension
tar -xzvf chrome.tgz; cd chrome; yum -y install google-chrome-stable --nogpgcheck; cp /usr/share/applications/google-chrome.desktop /home/xxx/Desktop; 桌面即有google-chrome.desktop文件,双击允许打开,...
Chrome是一款由Google公司开发的网页浏览器。该浏览器基于其他开源软件(如WebKit)撰写,目标是提升稳定性、速度和安全。Google Chrome 是一款快速、易用且安全的网络浏览器。此版 Chrome 是专为windows10 64位设计...
1,chrome 浏览器本身不支持直接调用exe,但可以使用url protocol handler 调用exe 2,直接双击exe_chrome.reg 安装注册表 3,test.html 要在运行在容器里(tomcat,resin XXXX),本地直接打开是执行不了的,我...
Chrome插件-Chrome Cleaner Pro为Chrome加速.zip。Chrome经过最近几年的发展, 强力的扩展越来越多, 离Chrome OS的目标也越来越近, 软件做大了就会有类似Windows的通病, 软件会变慢, 让Chrome变快的最简单方式就是...
chrome设置编码插件: chrome://extensions/