Chromium除了远近闻名的多进程架构之外,它的多线程模型也相当引人注目的。Chromium的多进程架构是为了解决网页的稳定性问题,而多线程模型则是为了解决网页的卡顿问题。为了达到这个目的,Chromium的多线程模型是基于异步通信的。
也就是说,一个线程请求另外一个线程运行一个任务的时候,不须要等待该任务完毕就能够去做其他事情。从而避免了卡顿。本文就分析Chromium的多线程模型的设计和实现。
老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注。
《Android系统源代码情景分析》一书正在进击的程序猿网(http://0xcc0xcd.com)中连载,点击进入。
有同学看到这里可能会有疑问,假设一个线程请求另外一个线程运行一个任务的时候。就是要等该任务完毕之后才干做其他事情。那么使用异步通信有什么用呢?的确如此,可是Chromium提供这样的基于异步通信的多线程模型。就是希望作为开发人员的你在实现一个模块的时候,尽最大努力地设计好各个子模块及其相应的数据结构。使得它们在协作时能够最大程度地进行异步通信。因此,Chromium基于异步通信的多线程模型很多其他的是体现一种设计哲学。
一个典型的异步通信过程如图1所看到的:
图1 线程异步通信过程
Task-1被分解成三个子任务Task-1(1)、Task-1(2)和Task-1(3)。
当中,Task-1(1)由Thread-1运行。
Task-1(1)运行完毕后。Thread-1通过我们在前面Chromium多线程通信的Closure机制分析一文分析的Closure请求Thread-2运行Task-1(2)。Task-1(2)运行完毕后,Thread-2又通过一个Closure请求Thread-1运行Task-1(3)。至此,Task-1就运行完毕。
我们能够将第一个Closure看作是一个Request操作。而第二个Closure是一个Reply操作。
这是一个典型的异步通信过程。
当然。假设不须要知道异步通信结果。那么第二个Closure和Task-1(3)就是不须要的。
假设Thread-1须要知道异步通信的结果,那么在图1中我们能够看到一个非常关键的点:Thread-1并非什么也不干就仅仅是等着Thread-2运行完毕Task-1(2),它趁着这个等待的空隙,干了另外一件事情——Task-2。假设我们将Thread-1看作是一个UI线程。那么就意味着这样的异步通信模式是能够提高它的响应性的。
为了能够完毕上述的异步通信过程。一个线程的生命周期如图2所看到的:
图2 线程生命周期
线程经过短暂的启动之后(Start),就环绕着一个任务队列(TaskQueue)不断地进行循环,直到被通知停止为止(Stop)。在环绕任务队列循环期间,它会不断地检查任务队列是否为空。假设不为空。那么就会将里面的任务(Task)取出来,而且进行处理。
这样,一个线程假设要请求另外一个线程运行某一个操作。那么仅仅须要将该操作封装成一个任务,而且发送到目标线程的任务队列去就可以。
为了更好地理解这样的基于任务队列的线程运行模式,我们脑补一下另外一种经常使用的基于锁的线程运行模式。一个线程要运行某一个操作的时候。就直接调用一个代表该操作的一个函数。假设该函数须要訪问全局数据或者共享数据。那么就须要进行加锁。避免其他线程也正在訪问这些全局数据或者共享数据。
这样做的一个优点是我们仅仅须要关心问题的建模,而不须要关心问题是由谁来运行的。仅仅要保证逻辑正确而且数据完整就可以。当然坏处也是显然的。首先是为了保持数据完整性,也就是避免訪问数据时出现竞争条件,代码里面充斥着各种锁。其次。假设多个线程同一时候获取同一个锁。那么就会产生竞争。
这样的锁竞争会带来额外的开销。从而减少线程的响应性。
基于任务队列的线程运行模式,要求在对问题进行建模时。要提前知道谁是运行者。也就是说。在对问题进行建模时。须要指派好每个子问题的运行者。这样我们为子问题设计数据结构时。就规定这些数据结构仅仅会被子问题的运行者訪问。这样运行者在解决指派给它的问题时,就不须要进行加锁操作,由于在解决问题过程中须要訪问的数据不会同一时候被其他运行者訪问。这就是通过任务队列来实现异步通信的多线程模型的设计哲学。
当然,这并非说,基于任务队列的线程运行模式能够全然避免使用锁,由于任务队列本身就是一个线程间的共享资源。想象一下,一个线程要往里面加入任务,还有一个线程要从里面将任务提取出来处理。因此,全部涉及到任务队列訪问的地方都是须要加锁的。可是假设我们再细致想想。那么就会发现。任务队列仅仅是一个基础设施,它与详细的问题是无关的。因此,仅仅要我们遵循上述设计哲学,就能够将代码里面须要加锁的地方仅限于訪问任务队列的地方,从而就能够减少锁竞争带来的额外的开销。
这样说来,似乎基于任务队列的线程运行模式非常好。可是实际上它对问题建模提出了更高的要求,也就是进行子问题划分时,要求划分出来的子问题是正交的。这样我们才有可能为这些子问题设计出不会同一时候被訪问的数据结构。看到“正交”两个字。是不是想起高数里面的向量空间的正交基了?或者傅里叶变换用到的一组三角函数了?事实上道理就是一样一样的。
好了。说了这么多,我们就步入到正题,分析Chromium多线程模型的设计和实现。也就是基于任务队列的线程运行模式涉及到核心类图。如图3所看到的:
图3 基于任务队列的线程运行模式核心类关系图
Thread是一个用来创建带消息循环的类。当我们创建一个Thread对象后,调用它的成员函数Start或者StartWithOptions就能够启动一个带消息循环的线程。
当中,成员函数StartWithOptions能够指定线程创建參数。当我们不须要这个线程时。就能够调用之前创建的Thread对象的成员函数Stop。
Thread类继承了PlatformThread::Delegate类,而且重写了它的成员函数ThreadMain。我们知道,Chromium是跨平台的。这样各个平台创建线程使用的API有可能是不一样的。只是。我们能够通过PlatformThread::Delegate类为各个平台创建的线程提供一个入口点。这个入口点就是PlatformThread::Delegate类的成员函数ThreadMain。由于Thread类重写了父类PlatformThread::Delegate的成员函数ThreadMain,因此不管是哪一个平台。当它创建完毕一个线程后,都会以Thread类的成员函数ThreadMain作为线程的入口点。
Thread类有一个重要的成员变量message_loop_,它指向的是一个MessageLoop对象。这个MessageLoop对象就是用来描写叙述线程的消息循环的。
MessageLoop类内部通过成员变量run_loop_指向的一个RunLoop对象和成员变量pump_指向的一个MessagePump对象来描写叙述一个线程的消息循环。
一个线程在运行的过程中。能够有若干个消息循环,也就是一个消息循环能够运行在另外一个消息循环里面。除了最外层的消息循环。其余的消息的消息循环称为嵌套消息循环。
我们为什么须要嵌套消息循环呢?这主要是跟模式对话框有关。
考虑一个情景,我们在一个窗体弹出一个文件选择对话框。
窗体必须要等到用户在文件选择对话框选择了文件之后。才干去做其他事情。窗体是在消息循环过程中打开文件对话框的。它要等待用户在文件选择对话框中选择文件 。就意味着消息循环被中止了。由于文件选择对话框也是通过消息循环来响应用户输入的,因此假设打开的它窗体中止了消息循环。就会导致它无法响应用户输入。为了解决问题。就要求打开文件选择的窗体不能中止消息循环。方法就是该窗体创建一个子消息循环,该子消息循环负责处理文件选择相应框的输入事件,直到用户选择了一个文件为止。
MessageLoop类的成员变量run_loop_指向的一个RunLoop对象就是用来记录线程当使用的消息循环的。RunLoop类有三个重要的成员变量:
1. message_loop_。记录一个RunLoop对象关联的MessageLoop对象。
2. previous_loop_,记录前一个消息循环,当就是包含当前消息循环的消息循环。
3. run_depth_,记录消息循环的嵌套深度。
MessageLoop类的成员变量pump_指向的一个MessagePump对象是用来进行消息循环的,也就是说,Thread类描写叙述的线程通过MessagePump类进入到消息循环中去。
Thread类将消息划分为三类,分别通过下面三个成员变量来描写叙述:
1. work_queue_,指向一个TaskQueue对象,用来保存那些须要立即处理的消息。
2. delayed_work_queue_。指向一个DelayedTaskQueue。用来保存那些须要延迟一段时间再处理的消息。
3. deferred_non_nestable_work_queue_。指向一个TaskQueue对象。用来保存那些不能够在嵌套消息循环中处理的消息。
一个MessagePump对象在进行消息循环时。假设发现消息队列中有消息,那么就须要通知关联的MessageLoop对象进行处理。
通知使用的接口就通过MessagePump::Delegate类来描写叙述。
MessagePump::Delegate类定义了四个成员函数,例如以下所看到的:
1. DoWork,用来通知MessageLoop类处理其成员变量work_queue_保存的消息。
2. DoDelayedWork。用来通知MessageLoop类处理其成员变量delayed_work_queue_保存的消息。
3. DoIdleWork。用来通知MessageLoop类当前无消息须要处理,MessageLoop类能够利用该间隙做一些Idle Work。
4. GetQueueingInformation,用来获取MessageLoop类内部维护的消息队列的信息。比如消息队列的大小。以及下一个延迟消息的处理时间。
有了前面的基础知识,接下来我们就能够大概描写叙述Thread类描写叙述的线程的运行过程。
首先是线程的启动过程:
1. 调用Thread类的成员函数Start或者StartWithOptions启动一个线程。而且以Thread类的成员函数ThreadMain作为入口点。
2. Thread类的成员函数ThreadMain负责创建消息循环,也就是通过MessageLoop类创建消息循环。
3. MessageLoop类在创建消息循环的过程中。会通过成员函数Init创建用来一个用来消息循环的MessagePump对象。
4. 消息循环创建完毕之后,调用MessageLoop类的成员函数Run进入消息循环。
5. MessageLoop类的成员函数Run创建一个RunLoop对象,而且调用它的成员函数Run进入消息循环。注意。该RunLoop对象在创建的过程,会关联上当前线程使用的消息循环,也就是创建它的MessageLoop对象。
6. RunLoop类的成员函数Run负责建立好消息循环的嵌套关系。也就是设置好它的成员变量previous_loop_和run_depth_等,然后就会调用其关联的MessageLoop对象的成员函数RunHandler进入消息循环。
7. MessageLoop类的成员函数RunHandler调用成员变量pump_描写叙述的一个MessagePump对象的成员函数Run进入消息循环。
接下来是向线程的消息队列发送消息的过程。这是通过MessageLoop类的下面四个成员函数向消息队列发送消息的:
1. PostTask,发送须要立即进行处理的而且能够在嵌套消息循环中处理的消息。
2. PostDelayedTask,发送须要延迟处理的而且能够在嵌套消息循环中处理的消息。
3. PostNonNestableTask。发送须要立即进行处理的而且不能够在嵌套消息循环中处理的消息。
4. PostNonNestableDelayedTask,发送须要延迟处理的而且不能够在嵌套消息循环中处理的消息。
向线程的消息队列发送了新的消息之后,须要唤醒线程,这是通过调用MessagePump类的成员函数Schedule进行的。线程被唤醒之后 。就会分别调用MessageLoop类重写父类MessagePump::Delegate的两个成员函数DoWork和DoDelayedWork对消息队列的消息进行处理。假设没有消息能够处理,就调用MessageLoop类重写父类MessagePump::Delegate的成员函数DoIdleWork通知线程进入Idle状态。这时候线程就能够做一些Idle Work。
MessageLoop类的成员函数DoWork在处理消息的过程中,依照下面三个类别进行处理:
1. 对于能够立即处理的消息,即保存在成员变量work_queue_描写叙述的消息队列的消息,运行它们的成员函数Run。
2. 对于须要延迟处理的消息,将它们保存在成员变量delayed_work_queue_描写叙述的消息队列中,而且调用成员变量pump_指向的一个MessagePump对象的成员函数ScheduleDelayedWork设置最早一个须要处理的延迟消息的处理时间。以便该MessagePump对象能够优化消息循环逻辑。
3. 对于能够立即处理可是不能够在嵌套消息循环中处理的消息,假设线程是处理嵌套消息循环中,那么将它们保存在成员变量deferred_non_nestable_work_queue_描写叙述的消息队列中。这些消息将会在线程进入Idle状态时,而且是处理最外层消息循环时,得到处理。
以上就是Thread类描写叙述的线程的大概运行过程,接下来我们通过源代码分析详细描写叙述这些过程。
我们首先看线程的启动过程。即Thread类的成员函数Start的实现,例如以下所看到的:
bool Thread::Start() {
Options options;
......
return StartWithOptions(options);
}
这个函数定义在文件external/chromium_org/base/threading/thread.cc中。
Thread类的成员函数Start调用另外一个成员函数StartWithOptions来启动一个线程。后者能够通过一个类型为Options的參数指定线程的启动參数,这里没有指定,意味着採用默认參数启动一个线程。
Thread类的成员函数StartWithOptions的实现例如以下所看到的:
bool Thread::StartWithOptions(const Options& options) {
......
StartupData startup_data(options);
startup_data_ = &startup_data;
if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
......
return false;
}
// Wait for the thread to start and initialize message_loop_
base::ThreadRestrictions::ScopedAllowWait allow_wait;
startup_data.event.Wait();
// set it to NULL so we don't keep a pointer to some object on the stack.
startup_data_ = NULL;
started_ = true;
......
return true;
}
这个函数定义在文件external/chromium_org/base/threading/thread.cc中。
Thread类的成员函数StartWithOptions首先是将线程启动參数封装一个在栈上分配的StartupData对象中。而且这个StartupData对象的地址会保存在Thread类的成员变量startup_data_中。接下来再调用由平台实现的PlatformThread类的静态成员函数Create创建一个线程。最后通过上面封装的StartupData对象的成员变量event描写叙述的一个WaitableEvent对象等待上述创建的线程启动完毕。
普通情况下。线程是不能够进入等待状态的,由于这样会减少线程的响应性。可是有时候线程不得不进入等待状态,比如如今这个情况,当前线程必须要等新创建的线程启动完毕之后才干返回。否则的话有可能新创建的线程还没有启动完毕。前面在栈上分配的StartupData对象就已经被释放,这样会导致新创建的线程无法訪问它的启动參数。
当新创建的线程启动完毕之后。就会通过上述的WaitableEvent对象唤醒当前线程。当前线程将Thread类的成员变量startup_data_置为NULL,避免它引用一个即将无效的在栈上分配的StartupData对象,而且将Thread类的成员变量started_的值设置为true。表示新创建的线程已经启动完毕。
接下来我们继续分析PlatformThread类的静态成员函数Create的实现。以Android平台为例,它的实现例如以下所看到的:
bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
PlatformThreadHandle* thread_handle) {
base::ThreadRestrictions::ScopedAllowWait allow_wait;
return CreateThread(stack_size, true /* joinable thread */,
delegate, thread_handle, kThreadPriority_Normal);
}
这个函数定义在文件external/chromium_org/base/threading/platform_thread_posix.cc中。
PlatformThread类的静态成员函数Create调用了另外一个函数CreateThread来创建一个线程,后者的实现例如以下所看到的:
bool CreateThread(size_t stack_size, bool joinable,
PlatformThread::Delegate* delegate,
PlatformThreadHandle* thread_handle,
ThreadPriority priority) {
......
bool success = false;
pthread_attr_t attributes;
pthread_attr_init(&attributes);
// Pthreads are joinable by default, so only specify the detached
// attribute if the thread should be non-joinable.
if (!joinable) {
pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
}
// Get a better default if available.
if (stack_size == 0)
stack_size = base::GetDefaultThreadStackSize(attributes);
if (stack_size > 0)
pthread_attr_setstacksize(&attributes, stack_size);
ThreadParams params;
params.delegate = delegate;
params.joinable = joinable;
params.priority = priority;
params.handle = thread_handle;
pthread_t handle;
int err = pthread_create(&handle,
&attributes,
ThreadFunc,
&ms);
success = !err;
......
pthread_attr_destroy(&attributes);
.....
return success;
}
这个函数定义在文件external/chromium_org/base/threading/platform_thread_posix.cc中。
从这里就能够看到。Android平台调用POSIX线程库中的函数pthread_create创建了一个线程,而且指定新创建的线程的入口点函数为ThreadFunc,同一时候传递给该入口点函数的參数为一个ThreadParams对象。该ThreadParams对象封装了线程启动过程中须要使用到的一系列參数。
新创建线程的入口点函数ThreadFunc的实现例如以下所看到的:
void* ThreadFunc(void* params) {
......
ThreadParams* thread_params = static_cast<ThreadParams*>(params);
PlatformThread::Delegate* delegate = thread_params->delegate;
......
delegate->ThreadMain();
......
return NULL;
}
这个函数定义在文件external/chromium_org/base/threading/platform_thread_posix.cc中。
函数ThreadFunc首先将參数params转换为一个ThreadParams对象。有了这个ThreadParams对象之后。就能够通过它的成员变量delegate获得一个PlatformThread::Delegate对象。从前面的调用过程能够知道,这个PlatformThread::Delegate对象实际上是一个Thread对象。用来描写叙述新创建的线程。得到了用来描写叙述新创建线程的Thread对象之后,就能够调用它的成员函数ThreadMain继续启动线程了。
Thread类的成员函数ThreadMain的实现例如以下所看到的:
void Thread::ThreadMain() {
{
......
scoped_ptr<MessageLoop> message_loop;
if (!startup_data_->options.message_pump_factory.is_null()) {
message_loop.reset(
new MessageLoop(startup_data_->options.message_pump_factory.Run()));
} else {
message_loop.reset(
new MessageLoop(startup_data_->options.message_loop_type));
}
......
message_loop_ = message_loop.get();
Init();
running_ = true;
startup_data_->event.Signal();
......
Run(message_loop_);
running_ = false;
......
message_loop_ = NULL;
}
}
这个函数定义在文件external/chromium_org/base/threading/thread.cc中。
回顾前面分析的Thread类的成员函数StartWithOptions,它已经将用来描写叙述线程启动參数的一个Options对象保存在成员变量startup_data_描写叙述的一个StartupData对象中,因此我们就能够又一次获取这个Options对象。
当Options类的成员变量message_pump_factory不等于NULL时。就表示新创建线程使用的Message Pump通过该成员变量描写叙述的一个Callback对象来创建。也就是调用该Callback对象的成员函数Run来创建。关于Chromium的Callback机制,能够參考前面Chromium多线程通信的Closure机制分析一文。有了Message Pump之后。就能够创建一个Message Loop了。该Message Loop终于会保存在Thread类的成员变量message_loop_中。
一般我们不通过Options类的成员变量message_pump_factory来创建Message Pump,而是通过另外一个成员变量message_loop_type来创建指定Message Loop的类型 ,从而确定要创建的Message Pump。这些逻辑都封装在MessageLoop类的构造函数中。
创建好Message Loop之后。线程的启动工作就完毕了,接下来新创建的线程就须要进入到初始化状态,这是通过调用Thread类的成员函数Init实现的。
Thread类的成员函数Init一般由子类重写,这样子类就有机会运行一些线程初始化工作。
再接下来,新创建的线程就须要进入运行状态,这是通过调用Thread类的成员函数Run实现的。
只是在新创建线程进入运行状态之前。还会做两件事情。第一件事情是将Thread类的成员变量running_设置为true,表示新创建的线程正在运行。第二件事情是通过Thread类的成员变量startup_data_指向的一个StartupData对象的成员变量event描写叙述的一个WaitableEvent唤醒请求创建新线程的线程。
最后。当Thread类的成员函数Run运行完毕返回后,须要将Thread类的成员变量running_和message_loop_分别重置为false和NULL,表示新创建的线程已经运行结束了,因此就不再须要Message Loop了。
接下来我们首先分析线程的Message Loop的创建过程,也就是MessageLoop类的构造函数的实现,以完毕线程的启动过程,然后再分析线程的运行过程,也就是Thread类的成员函数Run的实现。
我们假设线程的Message Loop是通过Message Loop Type来创建的,相应的MessageLoop类构造函数的实现例如以下所看到的:
MessageLoop::MessageLoop(Type type)
: type_(type),
nestable_tasks_allowed_(true),
......
run_loop_(NULL) {
Init();
pump_ = CreateMessagePumpForType(type).Pass();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc。
MessageLoop类的成员变量type_描写叙述的是消息循环的类型。nestable_tasks_allowed_描写叙述当前是否同意处理嵌套消息。runn_loop_描写叙述的是当前使用的消息循环。
MessageLoop类构造函数首先是调用成员函数Init运行初始化工作。接着再调用成员函数CreateMessagePumpForType依据消息循环的类型创建一个Message Pump。接下来我们就分别分析这两个成员函数的实现。
MessageLoop类的成员函数Init的实现例如以下所看到的:
LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
LAZY_INSTANCE_INITIALIZER;
......
void MessageLoop::Init() {
......
lazy_tls_ptr.Pointer()->Set(this);
incoming_task_queue_ = new internal::IncomingTaskQueue(this);
message_loop_proxy_ =
new internal::MessageLoopProxyImpl(incoming_task_queue_);
thread_task_runner_handle_.reset(
new ThreadTaskRunnerHandle(message_loop_proxy_));
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数Init首先将当前创建的MessageLoop对象保存在全局变量lazy_tls_ptr指向一块线程局部存储中,这样我们就能够通过MessageLoop类的静态成员函数current获得当前线程的消息循环,例如以下所看到的:
MessageLoop* MessageLoop::current() {
......
return lazy_tls_ptr.Pointer()->Get();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
回到MessageLoop类的成员函数Init中,接下来它创建了一个任务队列,而且保存在成员变量incoming_queue_中。这个任务队列通过IncomingQueue类来描写叙述。它的定义例如以下所看到的:
class BASE_EXPORT IncomingTaskQueue
: public RefCountedThreadSafe<IncomingTaskQueue> {
public:
......
bool AddToIncomingQueue(const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay,
bool nestable);
......
void ReloadWorkQueue(TaskQueue* work_queue);
......
void WillDestroyCurrentMessageLoop();
......
private:
......
TaskQueue incoming_queue_;
......
MessageLoop* message_loop_;
......
};
这个类定义在external/chromium_org/base/message_loop/incoming_task_queue.h中。
IncomingQueue类有两个重要的成员变量:
1. incoming_queue_。它描写叙述的是一个TaskQueue,代表的是线程的消息队列,也就是全部发送给线程的消息都保存在这里。
2. message_loop_,它指向一个MessageLoop对象。描写叙述的是线程的消息循环。
IncomingQueue类有三个重要的成员函数:
1. AddToIncomingQueue。用来向成员变量incoming_queue_描写叙述的消息队列发送一个消息,而且唤醒线程进行处理。
2. ReloadWorkQueue,用来提取成员变量incoming_queue_描写叙述的消息队列中的消息。而且保存在參数work_queue中。
3. WillDestroyCurrentMessageLoop。当该函数被调用时。会将成员变量message_loop_的值设置为NULL,使得我们不能够再向线程发送消息,也就是请求线程运行某一个操作。
IncomingQueue类的上述成员变量和成员函数我们后面分析消息的发送和处理再详细分析。如今返回到MessageLoop类的成员函数Init中,它接下来创建了一个MessageLoopProxyImpl对象和一个ThreadTaskRunnerHandle对象。分别保存在成员变量message_loop_proxy_和thread_task_runner_handle中,前者封装了当前线程的消息队列。后者又封装了前者。它们与MessageLoop类一样,都是能够用来向线程的消息队列发送消息。这意味着我们有三种方式向线程的消息队列发送消息。后面分析消息的发送过程时我们再详细分析。
MessageLoop类的成员函数Init运行完毕后,回到MessageLoop类的构造函数中,接下来它调用另外一个成员函数CreateMessagePumpForType依据消息循环的类型创建一个消息泵(Message Pump)。而且保存在成员变量pump_中。
MessageLoop类的成员函数CreateMessagePumpForType的实现例如以下所看到的:
#if defined(OS_IOS)
typedef MessagePumpIOSForIO MessagePumpForIO;
#elif defined(OS_NACL)
typedef MessagePumpDefault MessagePumpForIO;
#elif defined(OS_POSIX)
typedef MessagePumpLibevent MessagePumpForIO;
#endif
......
scoped_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) {
......
#if defined(OS_IOS) || defined(OS_MACOSX)
#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(MessagePumpMac::Create())
#elif defined(OS_NACL)
// Currently NaCl doesn't have a UI MessageLoop.
// TODO(abarth): Figure out if we need this.
#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>()
#else
#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(new MessagePumpForUI())
#endif
if (type == MessageLoop::TYPE_UI) {
if (message_pump_for_ui_factory_)
return message_pump_for_ui_factory_();
return MESSAGE_PUMP_UI;
}
if (type == MessageLoop::TYPE_IO)
return scoped_ptr<MessagePump>(new MessagePumpForIO());
#if defined(OS_ANDROID)
if (type == MessageLoop::TYPE_JAVA)
return scoped_ptr<MessagePump>(new MessagePumpForUI());
#endif
......
return scoped_ptr<MessagePump>(new MessagePumpDefault());
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
上面的代码通过一系列宏来适配不同的平台,这里我们仅仅考虑Android平台,这意味着MessagePumpForIO定义为MessagePumpLibevent,MESSAGE_PUMP_UI定义为scoped_ptr<MessagePump>(new MessagePumpForUI())。
从MessageLoop类的成员函数CreateMessagePumpForType的实现能够知道:
1. 假设消息循环的类型为MessageLoop::TYPE_UI,那么相应的消息泵为MessagePumpForUI。或者由函数指针message_pump_for_ui_factory_指向的函数创建。可是一般不设置函数指针message_pump_for_ui_factory_。因此,类型为MessageLoop::TYPE_UI的消息循环相应的消息泵为MessagePumpForUI。
在Chromium中,消息循环类型为MessageLoop::TYPE_UI的线程称为UI线程,也就是应用程序的主线程。
2. 假设消息循环的类型为MessageLoop::TYPE_IO,那么相应的消息泵为MessagePumpForIO,即MessagePumpLibevent。在Chromium中,消息循环类型为MessageLoop::TYPE_IO的线程称为IO线程,可是这里的IO不是读写文件的意思,而是运行IPC的意思。
3. 假设消息循环的类型为MessageLoop::TYPE_JAVA。那么相应的消息泵为MessagePumpForUI。在Chromium中,消息循环类型为MessageLoop::TYPE_JAVA的线程称为JAVA线程。它们与UI线程一样,在JAVA层具有自己的消息循环。
4. 其余类型的消息循环,相应的消息泵为MessagePumpDefault。
总结来说,就是在Android平台上,涉及到的消息泵有MessagePumpForUI、MessagePumpForIO和MessagePumpDefault三种。各自有不同的用途。当中MessagePumpForUI适用于在Java层具有自己的消息循环的UI线程和Java线程。MessagePumpLibevent适用于用来负责运行IPC的IO线程,MessagePumpDefault适用于其他的一般线程。我们先从一般性出发,分析MessagePumpDefault的实现,后面再分析MessagePumpForUI和MessagePumpForIO的实现。
MessagePumpDefault类继承于MessagePump类,它的定义例如以下所看到的:
class MessagePumpDefault : public MessagePump {
public:
MessagePumpDefault();
virtual ~MessagePumpDefault();
// MessagePump methods:
virtual void Run(Delegate* delegate) OVERRIDE;
virtual void Quit() OVERRIDE;
virtual void ScheduleWork() OVERRIDE;
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
private:
// This flag is set to false when Run should return.
bool keep_running_;
// Used to sleep until there is more work to do.
WaitableEvent event_;
// The time at which we should call DoDelayedWork.
TimeTicks delayed_work_time_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
};
这个类定义在文件external/chromium_org/base/message_loop/message_pump_default.h 。
MessagePumpDefault类重写了父类MessagePump的成员函数Run、Quit、ScheduleWork和ScheduleDelayedWork,后面我们分析消息循环的运行过程和消息的发送过程时,会看到它们的详细实现。
MessagePumpDefault类具有三个成员变量:
1. keep_running_。类型为bool,表示消息循环是否须要继续运行。
仅仅要线程不退出,消息循环就要持续运行。
2. event_,类型为WaitableEvent。表示一个能够进行Wait/Wake的事件变量。
当线程的消息队列为空时,线程就通过它进入到Wait状态,而当向线程的消息队列发送了一个消息时,就通过它唤醒线程。
3. delayed_work_time_,类型为TimeTicks,表示线程进入Wait状态的超时时间。达到超时时间之后,线程就会自己主动唤醒,然后处理那些延迟消息。
这样。一个消息循环及其相应的消息泵就创建完毕。回到Thread类的成员函数ThreadMain中。接下来它调用成员函数Run使得线程进入到运行状态。也就是环绕消息队列进行不断的循环,直到线程退出为止。
Thread类的成员函数Run的实现例如以下所看到的:
void Thread::Run(MessageLoop* message_loop) {
message_loop->Run();
}
这个函数定义在文件external/chromium_org/base/threading/thread.cc中。
Thread类的成员函数Run调用參数message_loop指向的一个MessageLoop对象的成员函数Run使得线程进入运行状态。
MessageLoop类的成员函数Run的实现例如以下所看到的:
void MessageLoop::Run() {
RunLoop run_loop;
run_loop.Run();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数Run在栈上创建了一个RunLoop对象。然后通过调用该RunLoop对象的成员函数Run使得线程进入运行状态。
前面提到,RunLoop的作用是用来建立消息循环的层次关系的,主要是通过它的两个成员变量previous_run_loop_和run_depth_来实现。此外,它还有一个成员变量loop_,用来关联它所相应的消息循环。
RunLoop类的上述三个成员变量的定义例如以下所看到的:
class BASE_EXPORT RunLoop {
public:
......
private:
......
MessageLoop* loop_;
// Parent RunLoop or NULL if this is the top-most RunLoop.
RunLoop* previous_run_loop_;
......
// Used to count how many nested Run() invocations are on the stack.
int run_depth_;
......
};
这三个成员变量定义在文件external/chromium_org/base/run_loop.h中。
它们在RunLoop类的构造函数被初始化,例如以下所看到的:
RunLoop::RunLoop()
: loop_(MessageLoop::current()),
previous_run_loop_(NULL),
run_depth_(0),
...... {
......
}
这个函数定义在文件external/chromium_org/base/run_loop.cc中。
从这里我们就能够看到,一个RunLoop关联的消息循环就是当前线程使用的消息循环。
这个消息循环能够通过调用前面提到的MessageLoop类的静态成员函数current获得。
RunLoop类的成员变量previous_run_loop_和run_depth_分别被初始化为NULL和0,表示还没有建立好层次关系。可是当RunLoop类的成员函数Run被调用时,它们就会被设置。从而形成层次关系。
从前面的调用过程能够知道,RunLoop类的成员函数Run在MessageLoop类的成员函数Run中调用。它的实现例如以下所看到的:
void RunLoop::Run() {
if (!BeforeRun())
return;
loop_->RunHandler();
AfterRun();
}
这个函数定义在文件external/chromium_org/base/run_loop.cc中。
在调用成员变量loop_指向的一个MessageLoop对象的成员函数RunHandler进入消息循环前后,RunLoop类的成员函数Run分别调用了BeforeRun和AfterRun两个成员函数,目的就是为了建立好消息循环的层次关系。它们的实现例如以下所看到的:
bool RunLoop::BeforeRun() {
DCHECK(!run_called_);
run_called_ = true;
// Allow Quit to be called before Run.
if (quit_called_)
return false;
// Push RunLoop stack:
previous_run_loop_ = loop_->run_loop_;
run_depth_ = previous_run_loop_?
previous_run_loop_->run_depth_ + 1 : 1; loop_->run_loop_ = this; running_ = true; return true; } void RunLoop::AfterRun() { running_ = false; // Pop RunLoop stack: loop_->run_loop_ = previous_run_loop_; // Execute deferred QuitNow, if any: if (previous_run_loop_ && previous_run_loop_->quit_called_) loop_->QuitNow(); }
这两个函数定义在文件external/chromium_org/base/run_loop.cc中。MessageLoop类的成员变量run_loop_记录的是消息循环当前使用的Run Loop,因此。RunLoop类的成员函数BeforeRun会将当前正在处理的RunLoop对象记录在其成员变量loop_指向的一个MessageLoop对象的成员变量run_loop_中。而该MessageLoop对象的成员变量run_loop_原来指向的RunLoop对象则记录在当前正在处理的RunLoop对象的成员变量previous_run_loop_中。从而就形成一个Run Loop调用栈。此外,第一个Run Loop的Run Depth被设置为1,后面的Run Loop的Run Depth依次添加1。
从上面的分析就能够看出。RunLoop类的成员函数BeforeRun运行的是一个Run Loop入栈操作,相应地,RunLoop类的成员函数AfterRun运行的是一个Run Loop出栈操作。它将消息循环当前使用的Run Loop恢复为前一个Run Loop。
RunLoop类的成员变量running_描写叙述的是一个Run Loop当前是否正在被消息循环使用,因此。在RunLoop类的成员函数BeforeRun和AfterRun中。它的值分别被设置为true和false。
RunLoop类的成员变量quit_called_描写叙述的是一个Run Loop是否收到退出请求。假设一个Run Loop当前正在消息循环使用。而且又收到了退出请求,那么就将会导致消息循环退出。
这样就会导致下面两种情况:
1. 一个Run Loop在即将被消息循环使用之前。就已经收到了退出请求,那么就不会被消息循环使用,表现就为在RunLoop类的成员函数BeforeRun中,假设当前正在处理的RunLoop对象的成员变量quit_called_的值等于true,那么就返回一个false值给调用者,表示当前正在处理的RunLoop对象不能够进入消息循环。
2. 一个Run Loop在被消息循环使用期间,前一个Run Loop收到了退出请求,那么当前Run Loop结束使用之后,禁止返回到前一个Run Loop。这意味着要结束消息循环。表现就为在RunLoop类的成员函数AfterRun中,假设发现当前正在处理的RunLoop对象的成员变量previous_run_loop_不为NULL,而且它指向的一个RunLoop对象的成员变量quit_called的值被设置为true。那么就会调用当前正在处理的RunLoop对象的成员变量loop_指向的一个MessageLoop对象的成员函数QuitNow退出消息循环。
回到RunLoop类的成员函数Run中,在调用成员函数BeforeRun成功建立好消息循环的层次关系之后,就通过当前正在处理的RunLoop对象进入到下一层消息循环中,这是通过调用当前正在处理的RunLoop对象的成员变量loop_指向的一个MessageLoop对象的成员函数RunHandler实现的。从前面的分析能够知道。该MessageLoop对象描写叙述的是就是当前线程使用的消息循环。
MessageLoop类的成员函数RunHandler的实现例如以下所看到的:
void MessageLoop::RunHandler() {
......
pump_->Run(this);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数RunHandler通过调用成员变量pump_指向的一个MessagePump对象的成员函数Run进入消息循环。
前面我们假设该MessagePump对象是一个MessagePumpDefault对象,因此接下来我们继续分析MessagePumpDefault类的成员函数Run的实现,例如以下所看到的:
void MessagePumpDefault::Run(Delegate* delegate) {
......
for (;;) {
......
bool did_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;
ThreadRestrictions::ScopedAllowWait allow_wait;
if (delayed_work_time_.is_null()) {
event_.Wait();
} else {
TimeDelta delay = delayed_work_time_ - TimeTicks::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_ = TimeTicks();
}
}
// Since event_ is auto-reset, we don't need to do anything special here
// other than service each delegate method.
}
keep_running_ = true;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_default.cc中。
參数delegate是一个Delegate类型的指针。可是从上面的调用过程能够知道,它指向的是一个MessageLoop对象。
MessagePumpDefault类的成员函数Run在一个for循环中不断地通过调用參数delegate指向的一个MessageLoop对象的成员函数DoWork和DoDelayedWork检查线程的消息队列是否有任务须要处理。假设没有。再调用该MessageLoop对象的成员函数DoIdleWork处理一些适用在线程空暇时进行的任务。
MessageLoop类的成员函数DoWork、DoDelayedWork和DoIdleWork的返回值均为一个布尔值。当这个布尔值等于true的时候,就表示线程处理了一些任务。在这样的情况下。就须要又一次运行一遍for循环,这是由于上述三个函数在处理任务的过程中,可能又往线程的消息队列发送了新的任务,因此须要for循环检查进行检查,以及新发送的任务能够得到及时处理。
还有一方面,假设MessageLoop类的成员函数DoWork、DoDelayedWork和DoIdleWork的返回值均为false,那就表示线程当前实在是无事可做。
这时候就不适合又一次运行一遍for循环,因此这会使得线程在空转。
在这样的情况下,最好的方式就是让线程进入睡眠状态。以便将CPU释放出来。
那么线程什么时候须要唤醒呢?
在两种情况下,线程须要从睡眠状态唤醒过来。第一种情况是线程的消息队列有新的消息加入的时候,这时候由发送消息的线程进行唤醒。
另外一种情况是,线程有一个延时消息须要处理,那么当系统达到该消息的处理时间时,线程就须要自己主动唤醒过来。
假设线程有一个延时消息须要处理,那么MessagePumpDefault类的成员变量delayed_work_time_就表示该消息在将来运行的时间点。注意,假设线程具有多个延时消息,那么MessagePumpDefault类的成员变量delayed_work_time_描写叙述的是最早的延时点,这时候线程最多就仅仅能睡眠到该时间点。然后自己主动唤醒过来。还有一点须要注意的是。假设最早的延时点小于系统的当前时间,那么线程就不能够睡眠,而要立即又一次运行for循环,以便能够对已经超过了时间点处理的消息进行处理。假设线程没有延时消息须要处理,那么线程就不会设置自己主动唤醒时间。而是一直处理睡眠状态,直到被其他线程唤醒为止。
不管线程是通过哪一种情况下进行睡眠状态。都是通过MessagePumpDefault类的成员变量event_描写叙述的一个WaitableEvent对象进行,即通过调用它的成员函数Wait和TimedWait进行的。
WaitableEvent是有效地实现线程消息循环的一个重要类。通过WaitableEvent类。线程能够在无消息处理时进入睡眠状态。而且在有消息处理时从睡眠状态唤醒过来,从而避免了不断地轮循消息队列是否有消息处理的操作。
由于消息队列可能在大多数情况下都是空的。对它进行不断轮循将会浪费CPU周期。
由于WaitableEvent类是如此重要,因此接下来我们先分析它的实现。然后再继续分析线程处理消息的过程。也就是MessageLoop类的成员函数DoWork、DoDelayedWork和DoIdleWork的实现。
WaitableEvent类的定义例如以下所看到的:
class BASE_EXPORT WaitableEvent {
public:
......
WaitableEvent(bool manual_reset, bool initially_signaled);
......
void Signal();
......
void Wait();
......
bool TimedWait(const TimeDelta& max_time);
......
class Waiter {
public:
......
virtual bool Fire(WaitableEvent* signaling_event) = 0;
......
virtual bool Compare(void* tag) = 0;
......
};
......
struct WaitableEventKernel :
public RefCountedThreadSafe<WaitableEventKernel> {
public:
WaitableEventKernel(bool manual_reset, bool initially_signaled);
bool Dequeue(Waiter* waiter, void* tag);
base::Lock lock_;
const bool manual_reset_;
bool signaled_;
std::list<Waiter*> waiters_;
......
};
......
bool SignalAll();
bool SignalOne();
void Enqueue(Waiter* waiter);
scoped_refptr<WaitableEventKernel> kernel_;
......
};
这个类定义在文件external/chromium_org/base/synchronization/waitable_event.h中。
这里我们仅仅讨论Android平台相关的实现。WaitableEvent类提供两个最基本的功能:Wait和Signal。Wait操作使得线程进入睡眠状态。而Signal操作使得线程从睡眠状态唤醒过来。
在WaitableEvent类中,Wait操作相应的两个成员函数为Wait和TimedWait。前者使得线程一直处理唤醒状态,直到被其他线程唤醒为止,而后者使得线程进入到睡眠状态的时间为有限时间。而且在超过该时间后。线程自己主动唤醒。
在WaitableEvent类中。Signal操作相应的成员函数为Signal,内部通成员函数SignalAll和SignalOne实现。前者唤醒全部的等待者,而后者仅仅唤醒当中一个等待者。
等待者通过内部类Waiter描写叙述,它有Fire和Compare两个成员函数。一个Waiter须要唤醒时,它的成员函数Fire就会被调用。
Waiter类的成员函数Compare用来比較一个Waiter与另外一个Waiter是否相同。
一个WaitableEvent能够有若干个Waiter。这些Waiter通过WaitableEvent类的成员函数Enqueue加入到成员变量kernel_指向的一个WaitableEventKernel对象的成员变量waiters_描写叙述的一个列表中。
WaitableEventKernel类除了上述的成员变量waiters_之外,还具有下面三个成员变量:
1. lock_。一个相互排斥锁,用来保护成员变量waiters_的并发訪问。
2. manual_reset_。一个布尔变量。用来表示一个WaitableEvent被唤醒的时候。是否须要手动设置才变为Signaled状态。
3. signaled_,一个布尔变量。用来表示一个WaitableEvent是否处于Signaled状态。
上述三个成员变量以及成员变量waiters_都是用来描写叙述一个WaitableEvent的状态的。为什么不将这些成员变量直接作为WaitableEvent类的成员变量呢?这是为了模拟Windows系统的HANDLE语意的。在Windows平台,一个描写叙述WaitableEvent对象的HANDLE处理等待状态时,是能够关闭的,即能够被Close。Windows平台觉得这样的情况会出现没有定义行为,可是不会导致程序Crash。
Android平台的WaitableEvent为具有这样的语意。就将描写叙述WaitableEvent状态的成员变量保存一个WaitableEventKernel对象中。然后通过一个scoped_refptr智能指针kernel_引用它。这样,当一个WaitableEvent被Close时,它本身是被销毁了。可是它的成员变量kernel_指向的WaitableEventKernel对象却未必会被销毁,这取决于其宿主WaitableEvent的使用情况。比如,假设这个WaitableEventKernel对象同一时候也被另外一个scoped_refptr智能指针引用时。由于它的引用计数大于1,那么它就不会被销毁。这意味着在我们能够有一种方式,使得一个WaitableEvent被销毁时。我们仍然能够通过其成员变量kernel_描写叙述的WaitableEventKernel对象操作该WaitableEvent,而且能够避免程序Crash。
我们先看WaitableEvent类的构造函数的实现。例如以下所看到的:
WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
: kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
WaitableEvent的构造函数主要就是创建了一个WaitableEventKernel对象。而且保存在成员变量kernel_中。
我们接下来继续分析WaitableEvent类的成员函数Wait的实现,例如以下所看到的:
void WaitableEvent::Wait() {
bool result = TimedWait(TimeDelta::FromSeconds(-1));
......
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
WaitableEvent类的成员函数Wait通过调用另外一个成员函数TimedWait使得线程进入睡眠状态,而且指定进入睡眠状态的时间为-1。即无限地进入睡眠状态,直到被其他线程唤醒为止。
WaitableEvent类的成员函数TimedWait的实现例如以下所看到的:所看到的:
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
......
const TimeTicks end_time(TimeTicks::Now() + max_time);
const bool finite_time = max_time.ToInternalValue() >= 0;
kernel_->lock_.Acquire();
if (kernel_->signaled_) {
if (!kernel_->manual_reset_) {
// In this case we were signaled when we had no waiters. Now that
// someone has waited upon us, we can automatically reset.
kernel_->signaled_ = false;
}
kernel_->lock_.Release();
return true;
}
SyncWaiter sw;
sw.lock()->Acquire();
Enqueue(&sw);
kernel_->lock_.Release();
for (;;) {
const TimeTicks current_time(TimeTicks::Now());
if (sw.fired() || (finite_time && current_time >= end_time)) {
const bool return_value = sw.fired();
......
sw.lock()->Release();
kernel_->lock_.Acquire();
kernel_->Dequeue(&sw, &sw);
kernel_->lock_.Release();
return return_value;
}
if (finite_time) {
const TimeDelta max_wait(end_time - current_time);
sw.cv()->TimedWait(max_wait);
} else {
sw.cv()->Wait();
}
}
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
我们分段来阅读WaitableEvent类的成员函数TimedWait的代码。
第一段代码例如以下所看到的:
const TimeTicks end_time(TimeTicks::Now() + max_time);
const bool finite_time = max_time.ToInternalValue() >= 0;
第一行代码计算线程进入睡眠状态的结束时间。保存在变量end_time中。
第二行代码推断參数max_time是否大于等于0。假设大于等于0。就意味着參数max_time描写叙述的是一个有限的时间,即线程不能无限进入睡眠状态。在这样的情况下,变量finite_time的值等于true。
否则的话,变量finite_time的值等于false。
第二段代码例如以下所看到的:
kernel_->lock_.Acquire();
if (kernel_->signaled_) {
if (!kernel_->manual_reset_) {
// In this case we were signaled when we had no waiters. Now that
// someone has waited upon us, we can automatically reset.
kernel_->signaled_ = false;
}
kernel_->lock_.Release();
return true;
}
这段代码推断当前处理的WaitableEvent是否已经处于Signaled状态。假设是的话。当前线程就不须要进入睡眠状态了。由于当前线程本来就是要等待当前处理的WaitableEvent处于Signaled状态的。在这样的情况下。WaitableEvent类的成员函数TimedWait就直接返回一个true值给调用者。表示已经成功地等待当前处理的WaitableEvent处于Signaled状态。
只是在返回之前。会推断当前处理的WaitableEvent在创建时是否指定了当它处于Signaled状态时。能够自己主动Reset为非Signaled状态。从这里我们就能够看出,一个WaitableEvent的状态能够从Signaled自己主动Reset为非Signaled。指的就是一个当其在Signaled状态时被运行Wait操作时,会自己主动变为非Signaled状态。这样在下一次运行Wait操作时,就要等到该WaitableEvent的状态变为Signaled之后,WaitableEvent类的成员函数TimedWait才会返回。
从这里我们就能够看到,WaitableEvent类的成员函数TimedWait是通过成员变量kernel_指向的一个WaitableEventKernel对象来获得Signaled状态的,从而能够避免一个WaitableEvent被销毁的时候,我们仍然能够訪问它的状态,而不会引发程序Crash。
从这里我们还能够看到,訪问WaitableEvent的状态须要在加锁的情况下进行,该锁由其成员变量kernel_指向的一个WaitableEventKernel对象的成员变量lock_描写叙述。同一时候,WaitableEvent类的成员函数TimedWait在返回之前。须要释放该锁。
第三段代码例如以下所看到的:
SyncWaiter sw;
sw.lock()->Acquire();
Enqueue(&sw);
kernel_->lock_.Release();
这段代码在栈上创建一个SyncWaiter对象,而且通过调用成员函数Enqueue将其加入到当前正在处理的WaitableEvent的Waiter列表中,例如以下所看到的:
void WaitableEvent::Enqueue(Waiter* waiter) {
kernel_->waiters_.push_back(waiter);
}
由于要操作当前正在处理的WaitableEvent的Waiter列表,因此WaitableEvent类的成员函数Enqueue须要在加锁的情况下进行操作。
SyncWaiter是一个用来描写叙述同步Waiter的类,所谓同步Waiter,就是说在线程进入睡眠状态这段时间,它是不会被销毁的。因此。在线程进入睡眠状态这段时间里,我们能够安全地对它进行操作。
SyncWaiter类的实现例如以下所看到的:
class SyncWaiter : public WaitableEvent::Waiter {
public:
SyncWaiter()
: fired_(false),
signaling_event_(NULL),
lock_(),
cv_(&lock_) {
}
virtual bool Fire(WaitableEvent* signaling_event) OVERRIDE {
base::AutoLock locked(lock_);
if (fired_)
return false;
fired_ = true;
signaling_event_ = signaling_event;
cv_.Broadcast();
return true;
}
WaitableEvent* signaling_event() const {
return signaling_event_;
}
virtual bool Compare(void* tag) OVERRIDE {
return this == tag;
}
bool fired() const {
return fired_;
}
void Disable() {
fired_ = true;
}
base::Lock* lock() {
return &lock_;
}
base::ConditionVariable* cv() {
return &cv_;
}
private:
bool fired_;
WaitableEvent* signaling_event_; // The WaitableEvent which woke us
base::Lock lock_;
base::ConditionVariable cv_;
};
这个类定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
SyncWaiter类的核心是定义了一个相互排斥锁lock_和一个条件变量cv_。它们分别能够通过成员函数lock和cv来获得。
SyncWaiter类有一个重要的成员函数Fire,它的作用唤醒睡眠在条件变量cv_的线程。而且将成员变量fired_设置为true,用来表示成员变量signaling_event_描写叙述的WaitableEvent已经处于Signaled状态。
我们继续分析WaitableEvent类的成员函数TimedWait的最后一段代码。例如以下所看到的:
for (;;) {
const TimeTicks current_time(TimeTicks::Now());
if (sw.fired() || (finite_time && current_time >= end_time)) {
const bool return_value = sw.fired();
......
sw.lock()->Release();
kernel_->lock_.Acquire();
kernel_->Dequeue(&sw, &sw);
kernel_->lock_.Release();
return return_value;
}
if (finite_time) {
const TimeDelta max_wait(end_time - current_time);
sw.cv()->TimedWait(max_wait);
} else {
sw.cv()->Wait();
}
}
这个for循环不断检查刚才已经加入到当前正在处理的WaitableEvent的Waiter列表的等待者sw是否已经被Fired。假设已经被Fired。那么就说明当前正在处理的WaitableEvent已经处理Signaled状态,因此就能够结束检查,而且返回了。
只是在返回之前,会调用WaitableEventKernel类的成员函数Dequeue将等待者sw从当前正在处理的WaitableEvent的Waiter列表删除。
WaitableEventKernel类的成员函数Dequeue的实现例如以下所看到的:
bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
for (std::list<Waiter*>::iterator
i = waiters_.begin(); i != waiters_.end(); ++i) {
if (*i == waiter && (*i)->Compare(tag)) {
waiters_.erase(i);
return true;
}
}
return false;
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
从这里我们能够看到。WaitableEventKernel类的成员函数Dequeue首先是在当前正在处理的WaitableEvent的Waiter列表找到參数waiter描写叙述的Waiter。然后再将其从列表中删除。
在当前正在处理的WaitableEvent的Waiter列表中查找參数waiter描写叙述的Waiter,不仅要对照列表的Waiter与參数waiter描写叙述的Waiter的地址是否相等,还要进一步以參数tag为參数。调用前者的成员函数Compare,仅仅有当该成员函数返回值等于true时。才会将參数waiter描写叙述的Waiter从列表中删除。
之所以要这样做。是与后面我们分析的异步Waiter有关的。这一点我们后面再详细分析。
回到WaitableEvent类的成员函数TimedWait的最后一段代码中。尽管等待者sw没有被Fired,可是WaitableEvent类的成员函数TimedWait的參数max_time指定了当前线程仅仅能够等待有限的时候,而且这个有限时间已经过去。在这样的情况下,即使等待者sw没有被Fired,那么WaitableEvent类的成员函数TimedWait也要返回了。只是这时候它的返回值为false。
最后,WaitableEvent类的成员函数TimedWait推断线程是否仅仅是有限地进入睡眠状态。即推断变量finite_time的值是否等于true。假设等于true,那么就会通过调用等待者sw内部的条件变量cv_的成员函数TimedWait使得当前线程进入睡眠状态,而且指定最长的睡眠时间为max_wait。
还有一方面,假设WaitableEvent类的成员函数TimedWait推断线程须要无限地进入睡眠状态,那么就会通过调用等待者sw内部的条件变量cv_的成员函数Timed使得当前线程进入无限睡眠状态,直到被其他线程唤醒为止。
我们最后继续分析WaitableEvent类的成员函数Signal的实现,例如以下所看到的:
void WaitableEvent::Signal() {
base::AutoLock locked(kernel_->lock_);
if (kernel_->signaled_)
return;
if (kernel_->manual_reset_) {
SignalAll();
kernel_->signaled_ = true;
} else {
// In the case of auto reset, if no waiters were woken, we remain
// signaled.
if (!SignalOne())
kernel_->signaled_ = true;
}
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
假设当前正在处理的WaitableEvent已经处于Signaled状态,那么WaitableEvent类的成员函数Signal就不须要再次将其改动为Signaled状态而且唤醒等待者了。否则的话,就继续往前运行。
假设当前正在处理的WaitableEvent的Signaled状态不可自己主动Reset为非Signaled状态,那么就调用成员函数SignalAll唤醒全部的等待者,而且保存当前正在处理的WaitableEvent的状态为Signaled状态。
假设当前正在处理的WaitableEvent的Signaled状态能够自己主动Reset为非Signaled状态,那么就调用成员函数SignalOne唤醒当中的一个等待者。
可是假设一个等待者都没有被唤醒,那么就会继续保持当前正在处理的WaitableEvent的状态为Signaled状态。
WaitableEvent类的成员函数SignalAll的实现例如以下所看到的:
bool WaitableEvent::SignalAll() {
bool signaled_at_least_one = false;
for (std::list<Waiter*>::iterator
i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
if ((*i)->Fire(this))
signaled_at_least_one = true;
}
kernel_->waiters_.clear();
return signaled_at_least_one;
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
WaitableEvent类的成员函数SignalAll对当前正在处理的WaitableEvent的Waiter列表中的每个Waiter,都调用其成员函数Fire。使得它们能够唤醒相应的线程。
最后。WaitableEvent类的成员函数SignalAll会清空当前正在处理的WaitableEvent的Waiter列表。而且在至少唤醒一个Waiter的情况下,返回一个true值给调用者,否则就返回false。
WaitableEvent类的成员函数SignalOne的实现例如以下所看到的:
bool WaitableEvent::SignalOne() {
for (;;) {
if (kernel_->waiters_.empty())
return false;
const bool r = (*kernel_->waiters_.begin())->Fire(this);
kernel_->waiters_.pop_front();
if (r)
return true;
}
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc中。
WaitableEvent类的成员函数SignalOne从当前正在处理的WaitableEvent的Waiter列表中的第一个Waiter開始,依次调用它们的成员函数Fire。
仅仅要当中的某一个Waiter的成员函数Fire的返回值为true,那么就会停止遍历Waiter列表,而且返回一个true值给调用者。
假设没有一个Waiter的成员函数Fire返回值为true,那么WaitableEvent类的成员函数SignalOne的返回值就为false。
注意。每个被遍历过的Waiter。不管它的成员函数Fire的返回值是什么,它都会从Waiter列表删除。
以上就是WaitableEvent通过同步等待者(SyncWaiter)实现的Wait和Signal操作。
WaitableEvent还能够通过异步等待者实现异步的Wait和Signal操作。为了理解这样的异步Wait和Signal操作,我们先看一个样例,例如以下所看到的:
class MyClass {
public:
void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
watcher_.StartWatching(waitable_event,
base::Bind(&MyClass::OnWaitableEventSignaled, this);
}
private:
void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
// OK, time to do stuff!
}
base::WaitableEventWatcher watcher_;
};
当我们调用MyClass类的成员函数DoStuffWhenSignaled的时候,表示希望在參数waitable_event描写叙述的一个WaitableEvent处于Signaled状态时,能够调用MyClass类的另外一个成员函数OnWaitableEventSignaled干点其他事情,这是通过成员变量watcher_描写叙述的一个WaitableEventWatcher对象的成员函数StartWatching实现的。
也就是说,通过WaitableEventWatcher类,我们能够监控一个WaitableEvent。使得它处于Signaled状态时。获得通知。
WaitableEventWatcher的定义例如以下所看到的:
class BASE_EXPORT WaitableEventWatcher
: public MessageLoop::DestructionObserver {
public:
typedef Callback<void(WaitableEvent*)> EventCallback;
WaitableEventWatcher();
virtual ~WaitableEventWatcher();
bool StartWatching(WaitableEvent* event, const EventCallback& callback);
void StopWatching();
......
private:
......
MessageLoop* message_loop_;
scoped_refptr<Flag> cancel_flag_;
AsyncWaiter* waiter_;
base::Closure internal_callback_;
scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
WaitableEvent* event_;
EventCallback callback_;
};
这个类定义在文件external/chromium_org/base/synchronization/waitable_event_watcher.h。
WaitableEventWatcher类有两个重要的成员函数StartWatching和StopWatching。前者用来监控一个WaitableEvent。而且当该WaitableEvent状态变成Signaled时,调用一个EventCallback,它的实现例如以下所看到的:
bool WaitableEventWatcher::StartWatching(
WaitableEvent* event,
const EventCallback& callback) {
MessageLoop *const current_ml = MessageLoop::current();
......
cancel_flag_ = new Flag;
callback_ = callback;
internal_callback_ =
base::Bind(&AsyncCallbackHelper, cancel_flag_, callback_, event);
WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
AutoLock locked(kernel->lock_);
event_ = event;
if (kernel->signaled_) {
if (!kernel->manual_reset_)
kernel->signaled_ = false;
// No hairpinning - we can't call the delegate directly here. We have to
// enqueue a task on the MessageLoop as normal.
current_ml->PostTask(FROM_HERE, internal_callback_);
return true;
}
message_loop_ = current_ml;
......
kernel_ = kernel;
waiter_ = new AsyncWaiter(current_ml, internal_callback_, cancel_flag_.get());
event->Enqueue(waiter_);
return true;
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
WaitableEventWatcher类的成员函数StartWatching首先是获得当前线程的消息循环。终于会保存在成员变量message_loop_,这样当參数event描写叙述的WaitableEvent状态变为Signaled时。将參数callback描写叙述的一个EventCallback发送到该消息循环去,然后在当前线程中运行。
接下来,WaitableEventWatcher类的成员函数StartWatching创建了一个Flag对象,而且保存在成员变量cancel_flag_中。这个Flag对象的作用是用来处理在异步等待WaitableEvent状态变为Signaled的过程中出现的异常情况的。由于是异步等待。因此就有可能要监控的WaitableEvent的状态还没有变为Signaled,进行监控的WaitableEventWatcher就已经被销毁。
比如,在前面举的样例中,我们创建一个MyClass对象,然后调用它的成员函数DoStuffWhenSignaled对一个WaitableEvent进行监控。
可是有可能该WaitableEvent的状态还没有变为Signaled,前面创建的MyClass对象就被销毁。这意味着它内部通过成员变量watcher_描写叙述的WaitableEventWatcher对象也会被销毁。
在这样的情况下。假设要监控的WaitableEvent状态变为Signaled。我们必须要保证已经被销毁的MyClass对象的成员函数OnWaitableEventSignaled不会被调用。否则的话就会出错了。
为了能够正确处理上述的异常情况,就必须要给一个WaitableEventWatcher关联一个生命周期更长的Flag对象,该Flag对象在要监控的WaitableEvent状态变为Signaled之前,不会被销毁。
Flag类的实现例如以下所看到的:
class Flag : public RefCountedThreadSafe<Flag> {
public:
Flag() { flag_ = false; }
void Set() {
AutoLock locked(lock_);
flag_ = true;
}
bool value() const {
AutoLock locked(lock_);
return flag_;
}
private:
friend class RefCountedThreadSafe<Flag>;
~Flag() {}
mutable Lock lock_;
bool flag_;
DISALLOW_COPY_AND_ASSIGN(Flag);
};
这个类定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
当一个WaitableEventWatcher被销毁时。与它关联的Flag对象的成员变量flag_的值就会被设置true,这意味着当监控的WatiableEvent状态变为Signaled时,不须要运行之前指定的一个EventCallback。
回到WaitableEventWatcher类的成员函数StartWatching中,接下来它创建一个Closure对象。而且保存在成员变量internal_callback_中,该Closure对象绑定的函数为AsyncCallbackHelper,而且当它被调用时,传递给它的參数前面创建的Flag对象。以及參数callback和event描写叙述的EventCallback对象和WaitableEvent对象。这样我们就能够推断出。当參数event描写叙述的WaitableEvent对象状态变为Signaled时,会通过函数AsyncCallbackHelper来间接地运行參数event描写叙述的EventCallback对象。
WaitableEventWatcher类的成员函数StartWatching接下来获得要监控的WaitableEvent内部的一个WaitableEventKernel对象,然后通过该WaitableEventKernel对象推断要监控的WaitableEvent的状态是否已经是Signaled。
假设是的话,那么就须要等待了。直接将前面创建的Closure发送到当前线程的消息循环去等待运行就可以。
最后,假设要监控的WaitableEvent的状态还没有变为Signaled。那么就须要进行等待了。
这是通过创建一个类型为AsyncWaiter的异步等待者。而且将它加入到要监控的WaitableEvent的Waiter列表中去实现的。这里我们就能够看到前面分析的同步等待和异步等待的差别。同步等待将一个SyncWaiter加入到一个WaitableEvent的Waiter列表去后,不能够立即返回,而是要通过一个for循环不断等待指定的WaitableEvent状态变为Signaled为止,或者直到等待的时候超出指定的时间为止。
AsyncWaiter类的实现例如以下所看到的:
class AsyncWaiter : public WaitableEvent::Waiter {
public:
AsyncWaiter(MessageLoop* message_loop,
const base::Closure& callback,
Flag* flag)
: message_loop_(message_loop),
callback_(callback),
flag_(flag) { }
virtual bool Fire(WaitableEvent* event) OVERRIDE {
// Post the callback if we haven't been cancelled.
if (!flag_->value()) {
message_loop_->PostTask(FROM_HERE, callback_);
}
// We are removed from the wait-list by the WaitableEvent itself. It only
// remains to delete ourselves.
delete this;
// We can always return true because an AsyncWaiter is never in two
// different wait-lists at the same time.
return true;
}
// See StopWatching for discussion
virtual bool Compare(void* tag) OVERRIDE {
return tag == flag_.get();
}
private:
MessageLoop *const message_loop_;
base::Closure callback_;
scoped_refptr<Flag> flag_;
};
这个类定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
从前面的分析能够知道,当要监控的WaitableEvent的状态变为Signaled时,前面已经已经加入到它的Waiter列表的AsyncWaiter对象的成员函数Fire就会被调用。
AsyncWaiter类的成员变量flag_指向的是一个Flag对象。前面提到,假设该Flag对象关联的WaitableEventWatcher在要监控的WaitableEvent状态还没有变为Signaled就已经被销毁,那么该Flag对象的成员变量flag_的值就会被设置为true。在这样的情况下。AsyncWaiter类的成员函数Fire就不须要运行成员变量callback_描写叙述的一个Closure。
还有一方面。假设AsyncWaiter类的成员变量flag_指向的Flag对象的成员变量flag_的值保持为false,那么就须要将成员变量callback_描写叙述的一个Closure发送到成员变量message_loop_描写叙述的一个消息循环去运行。
从前面的分析能够知道。AsyncWaiter类的成员变量message_loop_描写叙述的消息循环即为调用WaitableEventWatcher类的成员函数StartWatching的那个线程的消息循环,而且AsyncWaiter类的成员变量callback_描写叙述的Closure绑定的函数为AsyncCallbackHelper。它的实现例如以下所看到的:
void AsyncCallbackHelper(Flag* flag,
const WaitableEventWatcher::EventCallback& callback,
WaitableEvent* event) {
// Runs in MessageLoop thread.
if (!flag->value()) {
// This is to let the WaitableEventWatcher know that the event has occured
// because it needs to be able to return NULL from GetWatchedObject
flag->Set();
callback.Run(event);
}
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
參数flag描写叙述的Flag对象就是前面在WaitableEventWatcher类的成员函数StartWatching中创建的Flag对象。參数evnet描写叙述的就是要监控的WaitableEvent,而參数callback就是当參数evnet描写叙述的WaitableEvent状态变为Signaled时要运行的一个EventCallback。
仅仅有在參数flag描写叙述的Flag对象的成员变量flag_的值等于false的情况下,函数AsyncCallbackHelper才会运行參数callback描写叙述的EventCallback。而且在运行该EventCallback之前。会将參数flag描写叙述的Flag对象的成员变量flag_的值设置为true,用来表示參数callback描写叙述的EventCallback已经运行过了。
以上就是通过一个WaitableEventWatcher来监控一个WaitableEvent的状态变为Signaled而且获得通知的过程。前面我们还提及到一种情况。就是要监控的WaitableEvent的状态尚未变为Signaled,运行监控的WaitableEventWatcher就已经被销毁。
接下来我们就继续分析这样的情况是怎样处理的。
当一个WaitableEventWatcher被销毁时,它的析构函数就会被调用,例如以下所看到的:
WaitableEventWatcher::~WaitableEventWatcher() {
StopWatching();
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
WaitableEventWatcher类的析构函数调用另外一个成员函数StopWatching停止监控之前在成员函数StartWatching指定的WaitableEvent。
WaitableEventWatcher类的成员函数StopWatching的实现例如以下所看到的:
void WaitableEventWatcher::StopWatching() {
......
AutoLock locked(kernel_->lock_);
......
if (kernel_->Dequeue(waiter_, cancel_flag_.get())) {
....
delete waiter_;
internal_callback_.Reset();
cancel_flag_ = NULL;
return;
}
......
cancel_flag_->Set();
cancel_flag_ = NULL;
.....
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
WaitableEventWatcher类的成员函数StopWatching要处理的边界情况非常多,这里我们仅仅关心当中两个最基本的情况。
第一种情况是一个WaitableEventWatcher被销毁时,它要监控的WaitableEvent的状态依旧是没有变为Signaled。这时候该WaitableEventWatcher的成员变量waiter_指向的一个AsyncWaiter对象是在要监控的WaitableEvent的Waiter列表中。
因此这时候调用与该WaitableEvent关联的一个WaitableEventKernel对象的成员函数Dequeue能够将它从Waiter列表中删除,即调用上述WaitableEventKernel对象的成员函数Dequeue的返回值为true。这样就能够保证以后要监控的WaitableEvent的状态变为Signaled时,当前被销毁的WaitableEventWatcher不会获得任务通知。
另外一种情况是一个WaitableEventWatcher被销毁时。它要监控的WaitableEvent的状态已经变为Signaled。从前面的分析能够知道。这时候该WaitableEventWatcher的成员变量waiter_指向的一个AsyncWaiter对象已经不在要监控的WaitableEvent的Waiter列表了。而且它的成员函数Fire已经被调用。
可是该AsyncWaiter对象的成员变量callback_描写叙述的一个Closure可能还没有被调度运行。这时候就须要将与它关联的一个Flag对象的成员变量flag_的值设置为true,保证该Closure不会被运行。这个Flag对象就是WaitableEventWatcher类的成员变量cancel_flag指向的Flag对象。调用它的成员函数Set就可以将它的成员变量flag_的值设置为true。
这里有一点须要注意的是,WaitableEventWatcher类的成员函数StopWatching在调用WaitableEventKernel类的成员函数Dequeue从Waiter列表中删除成员变量waiter_描写叙述的一个AsyncWaiter时。传递的參数除了要删除的AsyncWaiter的地址外。还包含与它关联的一个Flag对象的地址。
为什么不能够仅仅传递要删除的AsyncWaiter的地址给WaitableEventKernel类的成员函数Dequeue呢?
这是为了处理一种称为ABA的问题的。
当一个AsyncWaiter被Fired时,它的成员函数Fire会被调用。而且这个成员函数在运行自我销毁的操作。
假设这时候恰好其他地方又创建了一个AsyncWaiter,而且这个新创建的AsyncWaiter被加入到了相同的WaitableEvent的Waiter列表中,更奇妙的是这个新创建的AsyncWaiter占用的内存与前面被销毁的AsyncWaiter占用的内存是全然一样的。这样就会导致前面调用WaitableEventKernel类的成员函数Dequeue删除了一个不该删除的AsyncWaiter!
注意。这样的情况仅仅会出如今异步等待WaitableEvent状态变为Signaled的情况。对于同步等待WaitableEvent状态变为Signaled的情况是没有这样的问题的。分析为了避免这样的情况。WaitableEventKernel类的成员函数Dequeue要求删除一个Waiter时,提供另外一个额外的參数tag,该參数会传递给即将被删除的Waiter的成员函数Compare。
仅仅有被删除的Waiter存在Waiter列表中,而且它的成员函数Compare的返回值也为true的情况下,WaitableEventKernel类的成员函数Dequeue才会将它从Waiter列表中删除,例如以下所看到的:
bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
for (std::list<Waiter*>::iterator
i = waiters_.begin(); i != waiters_.end(); ++i) {
if (*i == waiter && (*i)->Compare(tag)) {
waiters_.erase(i);
return true;
}
}
return false;
}
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_posix.cc。
AsyncWaiter类的成员函数Compare的实现例如以下所看到的:
class AsyncWaiter : public WaitableEvent::Waiter {
public:
......
// See StopWatching for discussion
virtual bool Compare(void* tag) OVERRIDE {
return tag == flag_.get();
}
private:
......
scoped_refptr<Flag> flag_;
};
这个函数定义在文件external/chromium_org/base/synchronization/waitable_event_watcher_posix.cc中。
从这里我们能够看到,仅仅有当參数tag的值等于AsyncWaiter类的成员变量flag_引用的一个Flag对象的地址值时。AsyncWaiter类的成员函数Compare的返回值才为true。
由于AsyncWaiter类的成员变量flag_是一个scoped_refptr智能指针,它引用的Flag对象同一时候也被关联的WatiableEventWatcher对象通过scoped_refptr智能指针引用。这意味着当一个AsyncWaiter被销毁时,它的成员变量flag_引用的Flag对象是仍然存在的,这样通过比較它的地址值与參数tag的值,就能够差别出两个前后分配在同一块内存的AsyncWaiter对象来。
至此,我们就分析完毕了WaitableEvent类是怎样实现线程在无消息处理时进入睡眠状态。而且在有消息处理时从睡眠状态唤醒过来的。
总结来说,就是通过条件变量来实现的。同一时候,我们还知道。WaitableEvent类不仅能够实现同步等待,还能够实现异步等待,前者通过配合SyncWaiter类实现,而后者通过配合AsyncWaiter类实现。异步等待,或者说异步操作。是Chromium的一大特色。
正是由于使用了大量的异步操作。Chromium才干做到高速地响应用户输入,从而使得用户感觉到Chromium在打开网页的时候非常快。
回到MessagePumpDefault类的成员函数Run中,我们前面提到。每次它通过成员变量event_描写叙述的一个WaitableEvent从睡眠状态唤醒过来之后。会依次调用參数delegate描写叙述的一个MessageLoop对象的成员函数DoWork和DoDelayedWork处理消息队列的消息以及成员函数DoIdleWork处理一些线程空暇时任务。
在分析MessageLoop类的成员函数DoWork、DoDelayedWork和DoIdleWork之前。我们首先分析向一个线程的消息队列发送消息的过程。
这是通过我们在前面提到的MessageLoop类的成员函数PostTask、PostDelayedTask、 PostNonNestableTask和PostNonNestableDelayedTask实现的。它们的定义例如以下所看到的:
void MessageLoop::PostTask(
const tracked_objects::Location& from_here,
const Closure& task) {
......
incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true);
}
void MessageLoop::PostDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
......
incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
}
void MessageLoop::PostNonNestableTask(
const tracked_objects::Location& from_here,
const Closure& task) {
......
incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false);
}
void MessageLoop::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
......
incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
}
这四个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的上述四个成员函数都是通过调用成员变量incoming_task_queue_描写叙述的一个IncomingTaskQueue对象的成员函数AddToIncomingQueue来发送參数task描写叙述的一个Closure对象到线程的消息队列去的。
IncomingTaskQueue类的成员函数AddToIncomingQueue的实现例如以下所看到的:
bool IncomingTaskQueue::AddToIncomingQueue(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay,
bool nestable) {
AutoLock locked(incoming_queue_lock_);
PendingTask pending_task(
from_here, task, CalculateDelayedRuntime(delay), nestable);
return PostPendingTask(&pending_task);
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
IncomingTaskQueue类的成员函数AddToIncomingQueue首先将參数task描写叙述的Closure封装在一个PendingTask中。然后调用另外一个成员函数PostPendingTask将它发送到线程的消息队列中去。由于消息队列既会被发送消息的线程操作,也会被处理消息的线程操作。因此它须要在加锁的前提下进行操作。这个锁通过IncomingTaskQueue类的成员变量incoming_queue_lock_描写叙述。
IncomingTaskQueue类的成员函数PostPendingTask的实现例如以下所看到的:
bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
......
// This should only be called while the lock is taken.
incoming_queue_lock_.AssertAcquired();
......
bool was_empty = incoming_queue_.empty();
incoming_queue_.push(*pending_task);
pending_task->task.Reset();
// Wake up the pump.
message_loop_->ScheduleWork(was_empty);
return true;
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
IncomingTaskQueue类的成员函数PostPendingTask首先是调用成员变量incoming_queue_lock_描写叙述的一个锁的成员函数AssertAcquired确保该锁已经被调用者获取。由于它接下来要操作线程的消息队列。
IncomingTaskQueue类的成员函数PostPendingTask接下来要做的事情非常简单。一是将參数pending_task描写叙述的一个PendingTask保存在成员变量incoming_queue_描写叙述的一个TaskQueue中,二是调用成员变量message_loop_描写叙述的一个MessageLoop的成员函数ScheduleWork唤醒线程对刚才加入在TaskQueue的PendingTask进行处理。
注意,在调用MessageLoop类的成员函数ScheduleWork的时候,传递有一个參数was_empty。该參数用来描写叙述在加入參数pending_task描写叙述的一个PendingTask到线程的消息队列之前,线程的消息队列是否为空。假设为空,意味着线程当前处于无限睡眠状态中。因此须要主动唤醒它。假设不为空,则说明线程当前要么正在运行,要么是处于一个会自己主动唤醒过来的睡眠状态中。
后面这样的情况不须要唤醒线程的。
MessageLoop类的成员函数ScheduleWork的实现例如以下所看到的:
bool AlwaysNotifyPump(MessageLoop::Type type) {
#if defined(OS_ANDROID)
return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
#else
return false;
#endif
}
......
void MessageLoop::ScheduleWork(bool was_empty) {
// The Android UI message loop needs to get notified each time
// a task is added to the incoming queue.
if (was_empty || AlwaysNotifyPump(type_))
pump_->ScheduleWork();
}
这两个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
如前所述。当參数was_empty的值等于true的时候,MessageLoop类的成员函数ScheduleWork就会调用成员变量pump_描写叙述的一个MessagePump对象的成员函数ScheduleWork来唤醒线程。
可是对于Android平台来说。假设当前正在处理的MessageLoop关联的是一个UI线程或者Java线程,不管參数was_empty的值是否为true,都须要唤醒它们。这是由于对于Android平台来说,UI线程和Java线程在Java层有着自己的消息循环,Native层的消息循环是借助于Java层的消息循环来实现的。这意味着线程的消息循环不是由Native来管理的,也就是Native层不知道Java的消息循环的管理逻辑,它就仅仅有每当有新的消息加入,都通知一下Java层对该消息进行处理。
后面我们再详细分析Android平台的UI线程和Java线程在Native层的消息循环的实现。
前面我们假设MessageLoop类的成员变量pump_指向的是一个MessagePumpDefault对象。因此接下来MessageLoop类的成员函数ScheduleWork调用的是MessagePumpDefault类的成员函数ScheduleWork。它的实现例如以下所看到的:
void MessagePumpDefault::ScheduleWork() {
// Since this can be called on any thread, we need to ensure that our Run
// loop wakes up.
event_.Signal();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_default.cc中。
前面分析MessagePumpDefault类的成员函数Run的时候提到,假设一个线程当前是处于睡眠状态的,那么它就是通过调用成员变量event_描写叙述的一个WaitableEvent的成员函数Wait或者TimedWait进入到睡眠状态的,因此如今就能够通过调用该WaitableEvent的成员函数Signal来唤醒它。这个唤醒过程能够參考前面分析的WaitableEvent类的成员函数Signal的实现。
线程被唤醒之后,如前所述。就会依次调用MessageLoop类的成员函数DoWork、DoDelayedWork和DoIdleWork。
MessageLoop类的成员函数DoWork的实现例如以下所看到的:
bool MessageLoop::DoWork() {
if (!nestable_tasks_allowed_) {
// Task can't be executed right now.
return false;
}
for (;;) {
ReloadWorkQueue();
if (work_queue_.empty())
break;
// Execute oldest task.
do {
PendingTask pending_task = work_queue_.front();
work_queue_.pop();
if (!pending_task.delayed_run_time.is_null()) {
AddToDelayedWorkQueue(pending_task);
// If we changed the topmost task, then it is time to reschedule.
if (delayed_work_queue_.top().task.Equals(pending_task.task))
pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
} else {
if (DeferOrRunPendingTask(pending_task))
return true;
}
} while (!work_queue_.empty());
}
// Nothing happened.
return false;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
在默认情况下,消息是禁止嵌套处理的,也就是说,线程在处理一个消息的过程时,不能够处理其他消息,这时候MessageLoop类的成员变量nestable_tasks_allowed_的值会被设置为false。因此,MessageLoop类的成员函数DoWork首先是推断成员变量nestable_tasks_allowed_的值是否等于false。假设等于的话。就什么也不做就返回了。
假设我们确实嵌套处理消息,那么须要通过ScopedNestableTaskAllower类暂时设置线程的MessageLoop同意运行嵌套消息,即将MessageLoop类的成员变量nestable_tasks_allowed_设置为true。
ScopedNestableTaskAllower类的实现例如以下所看到的:
class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
public:
......
// Enables nestable tasks on |loop| while in scope.
class ScopedNestableTaskAllower {
public:
explicit ScopedNestableTaskAllower(MessageLoop* loop)
: loop_(loop),
old_state_(loop_->NestableTasksAllowed()) {
loop_->SetNestableTasksAllowed(true);
}
~ScopedNestableTaskAllower() {
loop_->SetNestableTasksAllowed(old_state_);
}
private:
MessageLoop* loop_;
bool old_state_;
};
......
};
这个类定义在文件external/chromium_org/base/message_loop/message_loop.h中。
ScopedNestableTaskAllower类的构造函数调用了MessageLoop类的成员函数SetNestableTasksAllowed将线程的消息循环设置为可嵌套运行消息,而且在析构函数中也是调用MessageLoop类的成员函数SetNestableTasksAllowed将线程的消息循环设置为不可嵌套运行消息。
回到MessageLoop类的成员函数DoWork中,它接下来是通过两个循环不断地处理线程的消息队列的消息。直到该消息队列为空为止。
在外层的循环中。MessageLoop类的成员函数DoWork首先是调用另外一个成员函数ReloadWorkQueue将保存在成员变量incoming_task_queue_描写叙述的一个IncomingTaskQueue中的消息提取出来,保存在成员变量work_queue_描写叙述的一个TaskQueue中。然后再通过内层的循环对保存在该TaskQueue的每个消息进行处理。
MessageLoop类的成员函数ReloadWorkQueue的实现例如以下所看到的:
void MessageLoop::ReloadWorkQueue() {
......
if (work_queue_.empty())
incoming_task_queue_->ReloadWorkQueue(&work_queue_);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
在成员变员work_queue_描写叙述的TaskQueue为空的情况下。 MessageLoop类的成员函数ReloadWorkQueue调用成员变量incoming_task_queue_描写叙述的一个IncomingTaskQueue对象的成员函数ReloadWorkQueue将它里面消息都提取到成员变员work_queue_描写叙述的一个TaskQueue中。
IncomingTaskQueue类的成员函数ReloadWorkQueue的实现例如以下所看到的:
void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
......
// Acquire all we can from the inter-thread queue with one lock acquisition.
AutoLock lock(incoming_queue_lock_);
if (!incoming_queue_.empty())
incoming_queue_.Swap(work_queue); // Constant time
......
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
在成员变量incoming_queue_描写叙述的TaskQueue不为空的情况下, IncomingTaskQueue类的成员函数ReloadWorkQueue通过交换它和參数work_queue描写叙述的TaskQueue就可以将它里面的消息都提取给參数work_queue描写叙述的TaskQueue。
回到MessageLoop类的成员函数DoWork中,它接下来就通过内层循环对已经提取到成员变量work_queue_描写叙述的TaskQueue的消息进行处理,为了方便描写叙述,我们将相应的代码再列出来,例如以下所看到的:
// Execute oldest task.
do {
PendingTask pending_task = work_queue_.front();
work_queue_.pop();
if (!pending_task.delayed_run_time.is_null()) {
AddToDelayedWorkQueue(pending_task);
// If we changed the topmost task, then it is time to reschedule.
if (delayed_work_queue_.top().task.Equals(pending_task.task))
pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
} else {
if (DeferOrRunPendingTask(pending_task))
return true;
}
} while (!work_queue_.empty());
这段代码依次地将保存在成员变量work_queue_描写叙述的TaskQueue中的消息提取出来。每个消息都是通过一个PendingTask描写叙述的。
假设提取出来的消息是一个延迟处理的消息,即相应的PendingTask对象的成员变量delayed_run_time设置的时间不为空,那么就会调用MessageLoop类的成员函数AddToDelayedWorkQueue将它加入到另外一个延迟处理的消息队列中。假设该延迟消息被加入到了延迟处理消息队列的头部。那么就意味着要改动线程的下一次进入睡眠状态的时间长度,这是由于保存在处迟处理消息队列的消息是依照延迟处理时间从小到大的顺序排序的。
MessageLoop类的成员函数AddToDelayedWorkQueue的实现例如以下所看到的:
void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
// Move to the delayed work queue.
delayed_work_queue_.push(pending_task);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类使用的延迟处理消息队列由成员变量delayed_work_queue_描写叙述的一个DelayedTaskQueue对象表示。当调用它的成员函数push新加入一个PendingTask时。就会依据该PendingTask延迟运行时间点将放在队列的合适位置。使得队列始终是依照延迟运行时间点从小到大的顺序排列它里面的PendingTask。
改动线程的下一次进入睡眠状态的时间长度是通过调用MessageLoop类的成员变量pump_指向的一个MessagePumpDefault对象的成员函数ScheduleDelayedWork实现的,它的实现例如以下所看到的:
void MessagePumpDefault::ScheduleDelayedWork(
const TimeTicks& delayed_work_time) {
// We know that we can't be blocked on Wait right now since this method can
// only be called on the same thread as Run, so we only need to update our
// record of how long to sleep when we do sleep.
delayed_work_time_ = delayed_work_time;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_default.cc中。
MessagePumpDefault类的成员函数ScheduleDelayedWork仅仅是简单地将參数delayed_work_time描写叙述的时间保存在成员变量delayed_work_time_中。
等到MessageLoop类的成员函数DoWork运行完毕回到MessagePumpDefault类的成员函数Run时,该时间就会用来计算线程下一次要进入睡眠状态的时间长度。
最后。假设一个消息须要立即处理,那么MessageLoop类的成员函数DoWork的内层循环就会调用另外一个成员函数DeferOrRunPendingTask来对它进行处理。
MessageLoop类的成员函数DeferOrRunPendingTask的实现例如以下所看到的:
bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
if (pending_task.nestable || run_loop_->run_depth_ == 1) {
RunTask(pending_task);
// Show that we ran a task (Note: a new one might arrive as a
// consequence!).
return true;
}
// We couldn't run the task now because we're in a nested message loop
// and the task isn't nestable.
deferred_non_nestable_work_queue_.push(pending_task);
return false;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
參数pending_task描写叙述的消息能够立即运行须要满足下面两个条件之中的一个:
1. 參数pending_task描写叙述的消息是一个可嵌套处理的消息,即相应的PendingTask对象的成员变量nestable的值等于true。
2. 參数pending_task描写叙述的消息不是一个可嵌套处理的消息。可是线程当前运行在最外层的消息循环中。即MessageLoop类的成员变量run_loop_描写叙述的一个RunLoop对象的成员变量run_depth_的值等于1。
假设以上两个条件都不能满足,那么就将參数pending_task描写叙述的消息加入到成员变量deferred_non_nestable_work_queue_描写叙述的一个TaskQueue中等待在合适的时候再处理。
假设能满足以上两个条件之中的一个,那么就将參数pending_task描写叙述的消息就会被MessageLoop类的成员函数RunTask进行处理,例如以下所看到的:
void MessageLoop::RunTask(const PendingTask& pending_task) {
......
// Execute the task and assume the worst: It is probably not reentrant.
nestable_tasks_allowed_ = false;
......
pending_task.task.Run();
......
nestable_tasks_allowed_ = true;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
从这里就能够看到,MessageLoop类的成员函数RunTask在运行參数pending_task描写叙述的消息之前,会先将成员变量nestable_tasks_allowed_的值设置为false,用来禁止线程嵌套运行其他消息,而且在运行完毕參数pending_task描写叙述的消息的之后。将成员变量nestable_tasks_allowed_的值又一次设置为true。
从前面分析的MessageLoop类的成员函数PostTask、PostDelayedTask、 PostNonNestableTask和PostNonNestableDelayedTask的实现能够知道。參数pending_task描写叙述的消息实际上是一个Closure对象。该Closure对象保存在參数pending_task指向的一个PendingTask对象的成员变量task中。
从前面Chromium多线程通信的Closure机制分析一文能够知道。调用该Closure对象的成员函数Run就可以运行它描写叙述的任务。
接下来我们继续分析MessageLoop类的成员函数DoDelayedWork的实现,例如以下所看到的:
bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
recent_time_ = *next_delayed_work_time = TimeTicks();
return false;
}
......
TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
if (next_run_time > recent_time_) {
recent_time_ = TimeTicks::Now(); // Get a better view of Now();
if (next_run_time > recent_time_) {
*next_delayed_work_time = next_run_time;
return false;
}
}
PendingTask pending_task = delayed_work_queue_.top();
delayed_work_queue_.pop();
if (!delayed_work_queue_.empty())
*next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
return DeferOrRunPendingTask(pending_task);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
參数DoDelayedWork描写叙述的是下一个延迟处理消息的运行时间点。
假设线程的延迟处理消息队列空,那么MessageLoop类的成员函数DoDelayedWork就仅仅是简单地置空成员变量recent_time_和參数next_delayed_work_time描写叙述的时间变返回了。
还有一方面,与MessageLoop类的成员函数DoWork类似,MessageLoop类的成员函数DoDelayedWork也禁止处理嵌套消息。因此,当MessageLoop类的成员变量nestable_tasks_allowed_的值等于false的时候,MessageLoop类的成员函数DoDelayedWork就直接返回。
假设MessageLoop类的成员函数DoDelayedWork能够继续往下运行。那么它就检查位于延迟处理消息队列头部的消息,而且推断它的运行时间是否大于当前时间。假设是的话的,那么就说明该消息还未到时间运行,因此MessageLoop类的成员函数DoDelayedWork不会运行它,而是直接返回。
最后。假设位于延迟处理消息队列头部的消息的运行时间小于等于当前时间。那么就是时间将它从队列中取出,而且运行了。在运行之前,MessageLoop类的成员函数DoDelayedWork会获得下一个延迟处理消息的运行时间点,而且保存在參数next_delayed_work_time描写叙述的一个TimeTicks对象,以便返回到MessagePumpDefault类的成员函数Run的时候,后者能够计算出下一次进入睡眠状态的时间长度。
延迟处理消息相同是通过我们在前面分析的MessageLoop类的成员函数DeferOrRunPendingTask来运行的。因此这里不再复述。
接下来我们继续分析MessageLoop类的成员函数DoIdleWork的实现。例如以下所看到的:
bool MessageLoop::DoIdleWork() {
if (ProcessNextDelayedNonNestableTask())
return true;
if (run_loop_->quit_when_idle_received_)
pump_->Quit();
return false;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数DoIdleWork调用另外一个成员函数ProcessNextDelayedNonNestableTask处理那些被延迟的不能嵌套处理的消息。
假设线程没有被延迟的不能嵌套处理的消息,而且当前消息循环使用的RunLoop的成员变量quit_when_idle_received_的值被设置为true,即线程被设置在空暇时无事可做时,就会退出线程。这是通过调用成员变量pump_指向的一个MessagePumpDefault对象的成员函数Quit来实现的。
接下来我们主要分析MessageLoop类的成员函数ProcessNextDelayedNonNestableTask的实现,例如以下所看到的:
bool MessageLoop::ProcessNextDelayedNonNestableTask() {
if (run_loop_->run_depth_ != 1)
return false;
if (deferred_non_nestable_work_queue_.empty())
return false;
PendingTask pending_task = deferred_non_nestable_work_queue_.front();
deferred_non_nestable_work_queue_.pop();
RunTask(pending_task);
return true;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
被延迟的不能嵌套处理的消息保存在MessageLoop类的成员变量deferred_non_nestable_work_queue_描写叙述的一个TaskQueue中,这些消息仅仅能够在最外层的消息循环中运行。因此,MessageLoop类的成员函数ProcessNextDelayedNonNestableTask首先推断线程当前是否运行在最外层的消息循环中,即推断成员变量run_loop_指向的一个RunLoop对象的成员变量run_depth_的值是否等于1。
假设不等于1,那么就直接返回不往下运行了。
假设线程当前是运行在最外层的消息循环中。那么接下就从成员变量deferred_non_nestable_work_queue_描写叙述的一个TaskQueue的头部取出一个消息,而且调用前面分析过的成员函数RunTask对它进行处理。
至此,我们就分析完毕了线程的启动、环绕消息队列运行、发送消息和处理消息的过程了。当中,环绕消息队列运行这一过程是针对普通的线程的。对于Android平台的UI线程和Java线程。由于它们在Java层使用了Android系统提供的消息循环机制,因此假设我们须要在Native层使用Chromium提供的消息循环机制。就要进行特殊处理。接下来我们就继续分析怎样在Android平台的UI线程和Java线程中使用Chromium提供的消息循环机制。关于Android系统提供的消息循环机制,能够參考Android应用程序消息处理机制(Looper、Handler)分析一文。
对于Android平台的UI线程和Java线程来说,它们使用的消息循环和消息泵各自是通过MessageLoopForUI类和MessagePumpForUI类描写叙述的。这就差别于一般线程使用MessageLoop类和MesagePumpDefault来描写叙述消息循环和消息泵。接下来我们以UI线程为例来说明它是怎样使用Chromium提供的消息循环机制的。
对于Java线程,原理是一样的。
当我们在Android应用程序中使用WebView的时候。会在UI线程中调用BrowserMainRunnerImpl类的成员函数Initialize运行一些初始化工作。当中就包含在Native层中创建一个类型为MessageLoopForUI的消息循环。
在后面的文章中,我们分析WebView的启动过程时,就会看到这一过程。如今我们直接分析BrowserMainRunnerImpl类的成员函数Initialize的实现,例如以下所看到的:
class BrowserMainRunnerImpl : public BrowserMainRunner {
public:
......
virtual int Initialize(const MainFunctionParams& parameters) OVERRIDE {
......
if (!initialization_started_) {
initialization_started_ = true;
main_loop_.reset(new BrowserMainLoop(parameters));
......
main_loop_->EarlyInitialization();
......
main_loop_->MainMessageLoopStart();
......
}
......
int result_code = main_loop_->GetResultCode();
if (result_code > 0)
return result_code;
// Return -1 to indicate no early termination.
return -1;
}
......
};
这个函数定义在文件external/chromium_org/content/browser/browser_main_runner.cc。
BrowserMainRunnerImpl类的成员函数Initialize首先是创建了一个BrowserMainLoop对象,而且保存在成员变量main_loop_中。接下来再调用该BrowserMainLoop对象的成员函数EarlyInitialization运行早期初始化工作。
这个早期初始化工作就包含了创建一个类型为MessageLoopForUI的消息循环,例如以下所看到的:
void BrowserMainLoop::EarlyInitialization() {
......
if (parts_)
parts_->PreEarlyInitialization();
......
}
这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。
BrowserMainLoop类的成员变量parts_指向的是一个AwBrowserMainParts对象,这里调用它的成员函数PreEarlyInitialization创建一个类型为MessageLoopForUI的消息循环,例如以下所看到的:
void AwBrowserMainParts::PreEarlyInitialization() {
......
// Android WebView does not use default MessageLoop. It has its own
// Android specific MessageLoop. Also see MainMessageLoopRun.
DCHECK(!main_message_loop_.get());
main_message_loop_.reset(new base::MessageLoopForUI);
base::MessageLoopForUI::current()->Start();
}
这个函数定义在文件external/chromium_org/android_webview/browser/aw_browser_main_parts.cc中。
AwBrowserMainParts类的成员函数PreEarlyInitialization创建了一个MessageLoopForUI对象,接着再调用它的成员函数Start运行启动工作。
接下来我们先分析MessageLoopForUI对象的创建过程。即MessageLoopForUI类的构造函数的实现,例如以下所看到的:
class BASE_EXPORT MessageLoopForUI : public MessageLoop {
public:
MessageLoopForUI() : MessageLoop(TYPE_UI) {
}
......
};
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.h中。
MessageLoopForUI类继承了MessageLoop类。
MessageLoopForUI类的构造函数在调用父类MessageLoop的构造函数时,传递进去的參数为TYPE_UI,表示要创建一个类型为TYPE_UI的消息循环。从前面的分析能够知道,MessageLoop类的构造函数会依据传递给它的參数TYPE_UI创建一个类型为MessagePumpForUI的消息泵。而且保存在成员变量pump_中。
回到AwBrowserMainParts类的成员函数PreEarlyInitialization中,当它创建了一个MessageLoopForUI对象之后,接下来就会调用它的成员函数Start运行启动工作。例如以下所看到的:
void MessageLoopForUI::Start() {
// No Histogram support for UI message loop as it is managed by Java side
static_cast<MessagePumpForUI*>(pump_.get())->Start(this);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoopForUI类的成员变量pump_是从父类MessageLoop继承下来的。从前面的分析能够知道。它指向的是一个MessagePumpForUI对象。这里调用它的成员函数Start运行启动工作,例如以下所看到的:
void MessagePumpForUI::Start(Delegate* delegate) {
run_loop_ = new RunLoop();
// Since the RunLoop was just created above, BeforeRun should be guaranteed to
// return true (it only returns false if the RunLoop has been Quit already).
if (!run_loop_->BeforeRun())
NOTREACHED();
DCHECK(system_message_handler_obj_.is_null());
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
system_message_handler_obj_.Reset(
Java_SystemMessageHandler_create(
env, reinterpret_cast<intptr_t>(delegate)));
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_android.cc中。
MessagePumpForUI类的成员函数Start首先是创建了一个RunLoop对象,而且调用它的成员函数BeforeRun创建最外层的消息循环,接下来调用函数Java_SystemMessageHandler_create创建了一个Java层的SystemMessageHandler对象。而且保存在成员变量system_message_handler_obj_对象。
这个SystemMessageHandler对象就是Java层和Native层的消息循环之间进行通信的桥梁。
这样,Android应用程序的UI线程在Chromium中使用的消息循环就启动起来了。注意,Android应用程序的UI线程是在Java层环绕Android的消息队列运行的,因此它不能像普通的线程一样。也在Native层环绕Chromium的消息队列运行。也就是Android应用程序的UI线程不会调用MessageLoopForUI类的成员函数Run进入运行状态。
这一步运行完毕之后,一直返回到BrowserMainRunnerImpl类的成员函数Initialize,它接下来调用前面创建的BrowserMainLoop对象的成员函数MainMessageLoopStart,继续运行其他的初始化工作,例如以下所看到的:
void BrowserMainLoop::MainMessageLoopStart() {
......
InitializeMainThread();
......
}
这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。
BrowserMainLoop对象的成员函数MainMessageLoopStart运行的当中一个工作是调用另外一个成员函数InitializeMainThread初始化主线程,例如以下所看到的:
void BrowserMainLoop::InitializeMainThread() {
......
// Register the main thread by instantiating it, but don't call any methods.
main_thread_.reset(
new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current()));
}
这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。
BrowserMainLoop类的成员函数InitializeMainThread为主线程创建了一个BrowserThreadImpl对象,而且保存在成员变量main_thread_中。
BrowserThreadImpl对象的创建步骤例如以下所看到的:
BrowserThreadImpl::BrowserThreadImpl(ID identifier,
base::MessageLoop* message_loop)
: Thread(message_loop->thread_name()), identifier_(identifier) {
set_message_loop(message_loop);
Initialize();
}
这个函数定义在文件external/chromium_org/content/browser/browser_thread_impl.cc。
从前面的调用过程能够知道,參数identifier的值为BrowserThread::UI。而參数message_loop指向的是一个MessageLoopForUI对象。
BrowserThreadImpl类是从我们前面分析过的base::Thread类继承下来的,BrowserThreadImpl类调用的成员函数set_message_loop也是从父类base::Thread继承下来的,这里调用它来为UI线程设置一个消息循环。例如以下所看到的:
class BASE_EXPORT Thread : PlatformThread::Delegate {
public:
......
protected:
......
void set_message_loop(MessageLoop* message_loop) {
message_loop_ = message_loop;
}
......
private:
......
MessageLoop* message_loop_;
......
};
这个函数定义在文件external/chromium_org/base/threading/thread.h中。
这意味Android应用程序的UI线程尽管不像其他线程一样,不能在Native层环绕Chromium的消息队列运行,可是它也像其线程一样。使用一个Thead对象来描写叙述。而且这个Thread对象具有一个类型为MessageLoopForUI的消息循环。
返回到BrowserThreadImpl类的构造函数中。设置了Android应用程序的UI线程的消息循环之外。接下来调用另外一个成员函数Initialize运行其他的初始化工作,例如以下所看到的:
base::LazyInstance<BrowserThreadGlobals>::Leaky
g_globals = LAZY_INSTANCE_INITIALIZER;
......
void BrowserThreadImpl::Initialize() {
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
......
globals.threads[identifier_] = this;
}
这个函数定义在文件external/chromium_org/content/browser/browser_thread_impl.cc中。
BrowserThreadImpl类的成员函数Initialize做的工作实际上就是将用来描写叙述UI线程的一个BrowserThreadImpl对象注冊在全局变量g_globals指向的一个BrowserThreadGlobals对象的成员变量threads描写叙述的一个BrowserThreadImpl数组中。
有了这个BrowserThreadImpl数组之后,以后就能够通过BrowserThread类的静态成员函数PostTask、PostDelayedTask、PostNonNestableTask和PostNonNestableDelayedTask等向UI线程发送消息。以BrowserThread类的静态成员函数PostTask为例,调用它向UI线程发送消息的代码例如以下所看到的:
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
BrowserThread类的静态成员函数PostTask的实现例如以下所看到的:
bool BrowserThread::PostTask(ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task) {
return BrowserThreadImpl::PostTaskHelper(
identifier, from_here, task, base::TimeDelta(), true);
}
这个函数定义在文件external/chromium_org/content/browser/browser_thread_impl.cc中。
BrowserThread类的静态成员函数PostTask调用了BrowserThreadImpl类的静态成员函数PostTaskHelper向參数identifier描写叙述的线程的消息队列发送一个Closure。
BrowserThreadImpl类的静态成员函数PostTaskHelper的实现例如以下所看到的:
bool BrowserThreadImpl::PostTaskHelper(
BrowserThread::ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay,
bool nestable) {
......
base::MessageLoop* message_loop =
globals.threads[identifier] ?
globals.threads[identifier]->message_loop() : NULL; if (message_loop) { if (nestable) { message_loop->PostDelayedTask(from_here, task, delay); } else { message_loop->PostNonNestableDelayedTask(from_here, task, delay); } } ..... return !!message_loop; }
这个函数定义在文件external/chromium_org/content/browser/browser_thread_impl.cc中。
BrowserThreadImpl类的静态成员函数PostTaskHelper首先是依据參数identifier在前面描写叙述的全局变量g_globals指向的一个BrowserThreadGlobals对象的成员变量threads描写叙述的一个BrowserThreadImpl数组中获得一个相应的BrowserThreadImpl对象,接着再通过调用BrowserThreadImpl对象的成员函数message_loop获得一个MessageLoop对象。有了这个MessageLoop对象之后,就能够调用它的成员函数PostDelayedTask或者PostNonNestableDelayedTask向指定的线程的消息队列发送消息了。
前面我们已经分析过MessageLoop类的成员函数PostDelayedTask和PostNonNestableDelayedTask了。
从前面的分析能够知道。当它们向线程的消息队列发送了一个消息之后,最后会调用它的成员变量pump_描写叙述的一个MessagePump对象的成员函数ScheduleWork唤醒线程,以便它能够处理新发送到消息队列的消息。
从前面的分析能够知道。对于UI线程来说,它使用的消息循环通过类MessageLoopForUI来描写叙述,而MessageLoopForUI类的成员变量pump_指向的是一个MessagePumpForUI对象。MessagePumpForUI类是从MessagePump类继承下来的。而且重写了成员函数ScheduleWork,例如以下所看到的:
void MessagePumpForUI::ScheduleWork() {
DCHECK(!system_message_handler_obj_.is_null());
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_SystemMessageHandler_scheduleWork(env,
system_message_handler_obj_.obj());
}
这个函数定义在文件/external/chromium_org/base/message_loop/message_pump_android.cc中。
前面提到,MessagePumpForUI类的成员变量system_message_handler_obj_描写叙述的是一个Java层的SystemMessageHandler对象,这里通过函数Java_SystemMessageHandler_scheduleWork调用它的成员函数scheduleWork。
Java层的SystemMessageHandler类的成员函数scheduleWork的实现例如以下所看到的:
class SystemMessageHandler extends Handler {
......
@SuppressWarnings("unused")
@CalledByNative
private void scheduleWork() {
sendEmptyMessage(SCHEDULED_WORK);
}
......
}
这个函数定义在文件external/chromium_org/base/android/java/src/org/chromium/base/SystemMessageHandler.java中。
SystemMessageHandler类的成员函数scheduleWork调用从父类Handler继承下来的成员函数sendEmptyMessage向Java层的消息队列发送一个类型为SCHEDULED_WORK的消息,该消息终于地在SystemMessageHandler类的成员函数handleMessage中得到处理。例如以下所看到的:
class SystemMessageHandler extends Handler {
......
// Native class pointer set by the constructor of the SharedClient native class.
private long mMessagePumpDelegateNative = 0;
......
private SystemMessageHandler(long messagePumpDelegateNative) {
mMessagePumpDelegateNative = messagePumpDelegateNative;
}
@Override
public void handleMessage(Message msg) {
......
nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
}
......
}
这个函数定义在文件external/chromium_org/base/android/java/src/org/chromium/base/SystemMessageHandler.java中。
SystemMessageHandler类的成员变量mMessagePumpDelegateNative是在构造函数中初始化的,从前面分析的MessagePumpForUI的成员函数Start能够知道,它指向的是一个Native层的MessageLoopForUI对象。
SystemMessageHandler类的成员函数handleMessage调用JNI函数nativeDoRunLoopOnce通知成员变量mMessagePumpDelegateNative描写叙述的一个Native层的MessageLoopForUI对象,它的消息队列有新的消息须要处理。
SystemMessageHandler类的JNI函数nativeDoRunLoopOnce由Naitve层的函数Java_com_android_org_chromium_base_SystemMessageHandler_nativeDoRunLoopOnce实现,例如以下所看到的:
static void DoRunLoopOnce(JNIEnv* env, jobject jcaller,
jlong messagePumpDelegateNative,
jlong delayedScheduledTimeTicks);
__attribute__((visibility("default")))
void
Java_com_android_org_chromium_base_SystemMessageHandler_nativeDoRunLoopOnce(JNIEnv*
env, jobject jcaller,
jlong messagePumpDelegateNative,
jlong delayedScheduledTimeTicks) {
return DoRunLoopOnce(env, jcaller, messagePumpDelegateNative,
delayedScheduledTimeTicks);
}
这个函数定义在编译时自己主动生成的文件out/target/product/generic/obj/GYP/shared_intermediates/base/jni/SystemMessageHandler_jni.h中。
函数Java_com_android_org_chromium_base_SystemMessageHandler_nativeDoRunLoopOnce调用了另外一个函数DoRunLoopOnce通知UI线程在Native的消息队列有新的消息须要处理。
函数DoRunLoopOnce的实现例如以下所看到的:
static void DoRunLoopOnce(JNIEnv* env, jobject obj, jlong native_delegate,
jlong delayed_scheduled_time_ticks) {
base::MessagePump::Delegate* delegate =
reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
......
bool did_work = delegate->DoWork();
......
base::TimeTicks next_delayed_work_time;
did_work |= delegate->DoDelayedWork(&next_delayed_work_time);
if (!next_delayed_work_time.is_null()) {
......
if (delayed_scheduled_time_ticks == 0 ||
next_delayed_work_time < base::TimeTicks::FromInternalValue(
delayed_scheduled_time_ticks)) {
Java_SystemMessageHandler_scheduleDelayedWork(env, obj,
next_delayed_work_time.ToInternalValue(),
(next_delayed_work_time -
base::TimeTicks::Now()).InMillisecondsRoundedUp());
}
}
......
if (did_work)
return;
delegate->DoIdleWork();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_android.cc中。
函数DoRunLoopOnce首先是将參数native_delegate转化为一个Native层的base::MessagePump::Delegate对象。
在我们这个情景中,这个base::MessagePump::Delegate对象实际上是一个MessageLoopForUI对象。
接下来函数DoRunLoopOnce运行的工作与前面分析的MessagePumpDefault类的成员函数Run是类似的,差别主要在于:
1. 函数DoRunLoopOnce仅仅运行一次循环,而MessagePumpDefault类的成员函数Run运行的是无限循环。
2. 函数DoRunLoopOnce不能够进入睡眠状态。假设它有一个延迟处理的消息。那么须要通过函数Java_SystemMessageHandler_scheduleDelayedWork调用Java层的SystemMessageHandler类的成员函数scheduleDelayedWork来进行调度,而MessagePumpDefault类的成员函数Run能够自行进入睡眠状态来调度延迟处理消息的运行。
至此,我们就分析完毕Android应用程序的UI线程是怎样实现Chromium的消息循环了。
接下来我们继续分析另外一个特殊的消息循环。那就是负责运行IPC的IO线程的消息循环。
在前面分析的BrowserMainRunnerImpl类的成员函数Initialize中,除了我们提到它会调用BrowserMainLoop类的成员函数EarlyInitialization和MainMessageLoopStart来运行一些与UI线程相关的工作之外。还会调用BrowserMainLoop类的成员函数CreateStartupTasks来运行其他的启动任务。例如以下所看到的:
class BrowserMainRunnerImpl : public BrowserMainRunner {
public:
......
virtual int Initialize(const MainFunctionParams& parameters) OVERRIDE {
......
if (!initialization_started_) {
......
}
main_loop_->CreateStartupTasks();
int result_code = main_loop_->GetResultCode();
if (result_code > 0)
return result_code;
// Return -1 to indicate no early termination.
return -1;
}
......
};
这个函数定义在文件external/chromium_org/content/browser/browser_main_runner.cc中。
BrowserMainLoop类的成员函数CreateStartupTasks运行的启动任务非常多,这里我们仅仅关心与IO线程相关的任务,例如以下所看到的:
void BrowserMainLoop::CreateStartupTasks() {
......
if (!startup_task_runner_.get()) {
startup_task_runner_ = make_scoped_ptr(new StartupTaskRunner(
base::Bind(&BrowserStartupComplete),
base::MessageLoop::current()->message_loop_proxy()));
......
StartupTask create_threads =
base::Bind(&BrowserMainLoop::CreateThreads, base::Unretained(this));
startup_task_runner_->AddTask(create_threads);
......
if (BrowserMayStartAsynchronously()) {
startup_task_runner_->StartRunningTasksAsync();
}
}
if (!BrowserMayStartAsynchronously()) {
......
startup_task_runner_->RunAllTasksNow();
}
}
这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。
BrowserMainLoop类的成员函数CreateStartupTasks首先是会创建一个StartupTaskRunner对象,而且保存在成员变量startup_task_runner_中。
这个StartupTaskRunner对象封装了当前线程的一个消息循环,因此通过它能够向当前线程的消息队列发送消息。
当前线程即为Android应用程序的UI线程,因此有了这个StartupTaskRunner对象之后,接下来能够向UI线程的消息队列发送消息。
BrowserMainLoop类的成员函数CreateStartupTasks创建了一个用来创建线程的StartupTask,这个StartupTask绑定的函数为BrowserMainLoop类的成员函数CreateThreads,而且会保存在前面创建的一个StartupTaskRunner的内部等待运行。
最后,取决于Android应用程序的UI线程是使用同步还是异步方式来启动WebView。BrowserMainLoop类的成员函数CreateStartupTasks使用不同的方式来运行保存在成员变量startup_task_runner_指向的一个StartupTaskRunner对象中的StartupTask:
1. 假设是使用同步方式启动WebView。那么就调用上述StartupTaskRunner对象的成员函数RunAllTasksNow来运行保存在它里面的各个StartupTask对象的成员函数Run来运行它们。
2. 假设是使用异步方式启动WebView,那么就调用上述StartupTaskRunner对象的成员函数StartRunningTasksAsync向UI线程的消息队列发送一个消息。当该消息被处理时,再运行保存在上述StartupTaskRunner对象里面的各个StartupTask对象的成员函数Run。
不管是同步方式。还是异步方式,终于都会在UI线程调用BrowserMainLoop类的成员函数CreateThreads来创建一系列线程,例如以下所看到的:
int BrowserMainLoop::CreateThreads() {
......
base::Thread::Options default_options;
base::Thread::Options io_message_loop_options;
io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
......
for (size_t thread_id = BrowserThread::UI + 1;
thread_id < BrowserThread::ID_COUNT;
++thread_id) {
scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL;
base::Thread::Options* options = &default_options;
switch (thread_id) {
......
case BrowserThread::IO:
......
thread_to_start = &io_thread_;
options = &io_message_loop_options;
break;
......
default:
NOTREACHED();
break;
}
BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
if (thread_to_start) {
(*thread_to_start).reset(new BrowserProcessSubThread(id));
(*thread_to_start)->StartWithOptions(*options);
}
......
}
......
return result_code_;
}
这个函数定义在文件external/chromium_org/content/browser/browser_main_loop.cc中。
BrowserMainLoop类的成员函数CreateThreads创建了非常多线程。每个线程都有专门的作用。
这些线程的作用能够參考下面的枚举类型ID的定义:
class CONTENT_EXPORT BrowserThread {
public:
// An enumeration of the well-known threads.
// NOTE: threads must be listed in the order of their life-time, with each
// thread outliving every other thread below it.
enum ID {
// The main thread in the browser.
UI,
// This is the thread that interacts with the database.
DB,
// This is the thread that interacts with the file system.
FILE,
// Used for file system operations that block user interactions.
// Responsiveness of this thread affect users.
FILE_USER_BLOCKING,
// Used to launch and terminate Chrome processes.
PROCESS_LAUNCHER,
// This is the thread to handle slow HTTP cache operations.
CACHE,
// NOTE: do not add new threads here that are only used by a small number of
// files. Instead you should just use a Thread class and pass its
// MessageLoopProxy around. Named threads there are only for threads that
// are used in many places.
// This identifier does not represent a thread. Instead it counts the
// number of well-known threads. Insert new well-known threads before this
// identifier.
ID_COUNT
};
......
};
这个枚举类型定义在文件external/chromium_org/content/public/browser/browser_thread.h中。
回到BrowserMainLoop类的成员函数CreateThreads中,我们仅仅关注IO线程的创建过程。这个IO线程使用一个BrowserProcessSubThread对象来描写叙述。而且通过调用该BrowserProcessSubThread对象的成员函数StartWithOptions来启动。
BrowserProcessSubThread类是从BrowserThreadImpl类继承下来的。从前面的分析又能够知道,BrowserThreadImpl类又是从base::Thread类继承下来的。因此,Android应用程序中用来负责运行IPC的IO线程实际上是通过Thread类的成员函数StartWithOptions来创建,而且在创建的时候,指定创建的消息循环的类型为base::MessageLoop::TYPE_IO。
从前面分析的MessageLoop类的成员函数CreateMessagePumpForType的实现能够知道。类型为base::MessageLoop::TYPE_IO的消息循环使用的消息泵的通过类MessagePumpLibevent来描写叙述。
MessagePumpLibevent类是从MessagePump类继承下来的。它的定义例如以下所看到的:
class BASE_EXPORT MessagePumpLibevent : public MessagePump {
public:
......
MessagePumpLibevent();
......
// MessagePump methods:
virtual void Run(Delegate* delegate) OVERRIDE;
virtual void Quit() OVERRIDE;
virtual void ScheduleWork() OVERRIDE;
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
private:
......
// Libevent dispatcher. Watches all sockets registered with it, and sends
// readiness callbacks when a socket is ready for I/O.
event_base* event_base_;
// ... write end; ScheduleWork() writes a single byte to it
int wakeup_pipe_in_;
// ... read end; OnWakeup reads it and then breaks Run() out of its sleep
int wakeup_pipe_out_;
// ... libevent wrapper for read end
event* wakeup_event_;
......
};
这个类定义在文件external/chromium_org/base/message_loop/message_pump_libevent.h中。
MessagePumpLibevent类与前面分析的MessagePumpDefault类实现消息循环的最大差别是,前者通过Libevent实现线程睡眠与唤醒,而后者是通过条件变量实现线程睡眠与唤醒的。
Libevent在Android平台上实际上就是封装了由Linux内核提供的epoll机制。假设读过Android应用程序消息处理机制(Looper、Handler)分析这篇文章。Android应用程序使用的的消息循环机是基于epoll机制实现的。因此,Chromium里面的IO线程的消息循环机制与Android应用程序的消息循环机制的实现是非常类似的。接下来我们就简单分析Chromium里面的IO线程的消息循环的实现,主要就是分析MessagePumpLibevent类的构造函数、成员函数Run和ScheduleWork的实现。
MessagePumpLibevent类的构造函数的实现例如以下所看到的:
MessagePumpLibevent::MessagePumpLibevent()
: .....
event_base_(event_base_new()),
wakeup_pipe_in_(-1),
wakeup_pipe_out_(-1) {
if (!Init())
NOTREACHED();
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
MessagePumpLibevent类的构造函数主要就是调用成员函数Init初始化Libevent。例如以下所看到的:
bool MessagePumpLibevent::Init() {
int fds[2];
if (pipe(fds)) {
......
return false;
}
......
wakeup_pipe_out_ = fds[0];
wakeup_pipe_in_ = fds[1];
wakeup_event_ = new event;
event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
OnWakeup, this);
event_base_set(event_base_, wakeup_event_);
if (event_add(wakeup_event_, 0))
return false;
return true;
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
MessagePumpLibevent类的成员函数Init首先是创创建一个管道,而且分别将该管道的读端和写端文件描写叙述符保存在成员变量wakeup_pipe_out_和wakeup_pipe_in_中。
接下来,MessagePumpLibevent类的成员函数Init创建了一个Libevent里面的event。保存在成员变量wakeup_event_中,而且通过Libevent提供的函数event_set指定该event是用来监控文件描写叙述wakeup_pipe_out_的EV_READ和EV_PERSIST事件的,同一时候指定上述事件发生时,就调用MessagePumpLibevent类的静态成员函数OnWakeup。
这相当于是创建了一个epoll里面的epoll_event。
再接下来,MessagePumpLibevent类的成员函数Init通过Libevent提供的函数event_base_set创建了一个event_base。这相当于是通过epoll提供的函数epoll_create创建了一个epoll文件描写叙述符。
最后。MessagePumpLibevent类的成员函数Init通过调用Libevent提供函数event_add将前面创建的event加入到前面创建的event_base里面去。以便能够对指定的IO事件进行监控。这相当于是调用了epoll提供的函数epoll_ctl。
接下来,我们继续分析MessagePumpLibevent类的成员函数Run的实现,例如以下所看到的:
void MessagePumpLibevent::Run(Delegate* delegate) {
......
scoped_ptr<event> timer_event(new event);
for (;;) {
......
bool did_work = delegate->DoWork();
if (!keep_running_)
break;
event_base_loop(event_base_, EVLOOP_NONBLOCK);
did_work |= processed_io_events_;
processed_io_events_ = false;
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;
// EVLOOP_ONCE tells libevent to only block once,
// but to service all pending events when it wakes up.
if (delayed_work_time_.is_null()) {
event_base_loop(event_base_, EVLOOP_ONCE);
} else {
TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
if (delay > TimeDelta()) {
struct timeval poll_tv;
poll_tv.tv_sec = delay.InSeconds();
poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
event_base_set(event_base_, timer_event.get());
event_add(timer_event.get(), &poll_tv);
event_base_loop(event_base_, EVLOOP_ONCE);
event_del(timer_event.get());
} else {
// It looks like delayed_work_time_ indicates a time in the past, so we
// need to call DoDelayedWork now.
delayed_work_time_ = TimeTicks();
}
}
}
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
与MessagePumpDefault类的成员函数Run相比,MessagePumpLibevent类的成员函数Run的运行流程是类似的。主要差别在于:
1. MessagePumpLibevent类通过调用Libevent提供的函数event_base_loop使得线程进入睡眠状态。而MessagePumpDefault类通过条件变量使得程进入睡眠状态。
2. MessagePumpLibevent除了用来监控消息队列有无新增消息之后,还用来监控指定的文件描写叙述符的IO事件,例如以下面代码所看到的:
event_base_loop(event_base_, EVLOOP_NONBLOCK);
did_work |= processed_io_events_;
processed_io_events_ = false;
if (!keep_running_)
break;
这段代码调用Libevent提供的函数event_base_loop检查其他指定监控的文件描写叙述是有IO事件发生。
假设有发生的话,就调用它们指定的回调函数进行处理。注意。这里调用函数event_base_loop时,第二个參数指定为EVLOOP_NONBLOCK,表示在没有IO事件发生的情况下,不会堵塞当前线程的运行。
在调用函数event_base_loop时,假设第二个參数指定为EVLOOP_ONCE,则表示在没有IO事件发生的情况下。会堵塞当前线程的运行,直到有IO事件发生,或者指定的堵塞时间超时为止。
这相当于是调用了epoll提供的函数epoll_wait。
接下来我们继续分析MessagePumpLibevent类的成员函数ScheduleWork的实现,例如以下所看到的:
void MessagePumpLibevent::ScheduleWork() {
// Tell libevent (in a threadsafe way) that it should break out of its loop.
char buf = 0;
int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
DCHECK(nwrite == 1 || errno == EAGAIN)
<< "[nwrite:" << nwrite << "] [errno:" << errno << "]";
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
MessagePumpLibevent类的成员函数ScheduleWork向成员变量wakeup_pipe_in_描写叙述的管道写入一个字符,从前面分析的MessagePumpLibevent类的成员函数Init能够知道,这将会导致MessagePumpLibevent类的静态成员函数OnWakeup被调用,例如以下所看到的:
void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
MessagePumpLibevent* that = static_cast<MessagePumpLibevent*>(context);
DCHECK(that->wakeup_pipe_out_ == socket);
// Remove and discard the wakeup byte.
char buf;
int nread = HANDLE_EINTR(read(socket, &buf, 1));
DCHECK_EQ(nread, 1);
that->processed_io_events_ = true;
// Tell libevent to break out of inner loop.
event_base_loopbreak(that->event_base_);
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
MessagePumpLibevent类的静态成员函数OnWakeup首先是调用函数read将前面写入到管道的字符读取出来,而且调用Libevent提供的函数event_base_loopbreak使得MessagePumpLibevent类的成员函数Run能够从函数event_base_loop返回,以便能够去处理消息队列的消息。
前面提到,MessagePumpLibevent除了用来监控消息队列之外。还能够用来监控指定文件描写叙述符的IO事件。这是通过调用MessagePumpLibevent类的成员函数WatchFileDescriptor实现的,例如以下所看到的:
bool MessagePumpLibevent::WatchFileDescriptor(int fd,
bool persistent,
int mode,
FileDescriptorWatcher *controller,
Watcher *delegate) {
......
int event_mask = persistent ?
EV_PERSIST : 0; if (mode & WATCH_READ) { event_mask |= EV_READ; } if (mode & WATCH_WRITE) { event_mask |= EV_WRITE; } scoped_ptr<event> evt(controller->ReleaseEvent()); if (evt.get() == NULL) { // Ownership is transferred to the controller. evt.reset(new event); } else { // Make sure we don't pick up any funky internal libevent masks. int old_interest_mask = evt.get()->ev_events & (EV_READ | EV_WRITE | EV_PERSIST); // Combine old/new event masks. event_mask |= old_interest_mask; // Must disarm the event before we can reuse it. event_del(evt.get()); if (EVENT_FD(evt.get()) != fd) { ...... return false; } } // Set current interest mask and message pump for this event. event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller); // Tell libevent which message pump this socket will belong to when we add it. if (event_base_set(event_base_, evt.get())) { return false; } // Add this socket to the list of monitored sockets. if (event_add(evt.get(), NULL)) { return false; } // Transfer ownership of evt to controller. controller->Init(evt.release()); controller->set_watcher(delegate); controller->set_pump(this); return true; }
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
各个參数的含义例如以下所看到的:
1. fd:要监控其IO事件的文件描写叙述符。
2. persistent:是否要持续监控參数mode描写叙述的IO事件。
3. mode:详细的IO事件。比如读写事件等。
4. controller:指向一个负责接收IO事件通知的FileDescriptorWatcher对象。
5. delegate:指向一个Watcher对象,參数controller将接收到的IO事件转发给它处理。
MessagePumpLibevent类的成员函数WatchFileDescriptor首先是依据參数persistent和mode初始化好一个event_mask。接下来调用event_set设置一个代表IO监控事件的event时要用到。
MessagePumpLibevent类的成员函数WatchFileDescriptor接下来调用參数controller描写叙述的一个FileDescriptorWatcher对象的成员函数ReleaseEvent检查其内部是否提供了一个event。假设没有提供。那么创建一个新的event。以便用来监控文件描写叙述符fd的IO事件。假设有提供,则复用它。复用不仅仅是event对象本身,还包含该event对象原来设置的event_mask。同一时候,能够复用有一个前提,就是被复用的event关联的文件描写叙述符必须要与參数fd描写叙述的文件描写叙述符一致。
MessagePumpLibevent类的成员函数WatchFileDescriptor接下来调用Libevent提供的函数event_set又一次设置前面获得的event的属性。包含它要监控的文件描写叙述符、要监控的详细IO事件、以及监控的IO事件发生时的回调函数等。从这里就能够看到。当文件描写叙述符fd指定的IO事件发生时,MessagePumpLibevent类的静态成员函数OnLibeventNotification就会被调用。而且会获得參数controller指向的一个FileDescriptorWatcher对象。
MessagePumpLibevent类的成员函数WatchFileDescriptor接下来调用Libevent提供的函数event_base_set和event_add将前面已经设置好属性的event添加到成员变量event_base_描写叙述的一个事件监控对象中去。
MessagePumpLibevent类的成员函数WatchFileDescriptor最后将用来描写叙述IO事件监控的event、负责处理IO事件的Watcher和以及当前正在处理的一个MessagePumpLibevent对象设置到參数controller描写叙述的一个FileDescriptorWatcher对象的内部去,以便该FileDescriptorWatcher对象在接收到IO事件通知时能够进行相应的处理。
接下来我们再看被监控的文件描写叙述符发生指定的IO事件时的处理流程。即MessagePumpLibevent类的静态成员函数OnLibeventNotification的实现,例如以下所看到的:
void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
void* context) {
WeakPtr<FileDescriptorWatcher> controller =
static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
DCHECK(controller.get());
MessagePumpLibevent* pump = controller->pump();
pump->processed_io_events_ = true;
if (flags & EV_WRITE) {
controller->OnFileCanWriteWithoutBlocking(fd, pump);
}
// Check |controller| in case it's been deleted in
// controller->OnFileCanWriteWithoutBlocking().
if (controller.get() && flags & EV_READ) {
controller->OnFileCanReadWithoutBlocking(fd, pump);
}
}
这个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
从前面的分析能够知道。參数context指向的一个FileDescriptorWatcher对象,因此MessagePumpLibevent类的静态成员函数OnLibeventNotification首先是将它强制转化为一个FileDescriptorWatcher对象,而且获得一个引用了它的WeakPtr弱智能指针。
关于WeakPtr弱智能指针的实现和使用方式,能够參考前面Chromium和WebKit的智能指针实现原理分析一文。
这里为什么要获得參数context指向的一个FileDescriptorWatcher对象的一个弱智能指针呢?这是由于后面调用它的成员函数OnFileCanWriteWithoutBlocking时,然后该成员函数OnFileCanWriteWithoutBlocking将IO事件分发给它内部的一个Watcher处理时,该FileDescriptorWatcher对象可能会被销毁。为了不阻止该FileDescriptorWatcher对象销毁。于是就使用WeakPtr弱智能指针引用它了。
MessagePumpLibevent类的静态成员函数OnLibeventNotification接下来调用前面获得的FileDescriptorWatcher对象的成员函数pump获得一个与它关联的MessagePumpLibevent对象,而且将它的成员变量processed_io_events_的值设置为true,表示关联的MessagePumpLibevent对象有新的IO事件须要处理。这个设置将会影响到前面分析的MessagePumpLibevent类的成员函数Run的运行。由于在这样的情况下。MessagePumpLibevent类的成员函数Run不能够去处理延迟消息、也不能运行Idle Work以及进入睡眠等待状态,而是要立即又一次运行一次for循环。以及检查有没有很多其他的须要立即处理IO事件须要处理。
MessagePumpLibevent类的静态成员函数OnLibeventNotification最后就通过參数flags检查详细发生的IO事件,而且运行相应的处理:
1. 假设发生的是写事件。那么就调用參数context指向的一个FileDescriptorWatcher对象的成员函数OnFileCanWriteWithoutBlocking进行处理。
2. 假设发生的是读事件,那么就调用參数context指向的一个FileDescriptorWatcher对象的成员函数OnFileCanReadWithoutBlocking进行处理。
如上所述。前面在处理写事件的过程中,有可能參数context指向的一个FileDescriptorWatcher对象已经被销毁,因此,这里要先调用一下WeakPtr弱智能指针controller的成员函数get推断它是否真的已经被销毁。假设已经被销毁,那么就不须要调用它的成员函数OnFileCanReadWithoutBlocking了。
FileDescriptorWatcher类的成员函数OnFileCanWriteWithoutBlocking和OnFileCanReadWithoutBlocking的实现例如以下所看到的:
void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
int fd, MessagePumpLibevent* pump) {
// Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
// watching the file descriptor.
if (!watcher_)
return;
pump->WillProcessIOEvent();
watcher_->OnFileCanReadWithoutBlocking(fd);
pump->DidProcessIOEvent();
}
void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
int fd, MessagePumpLibevent* pump) {
DCHECK(watcher_);
pump->WillProcessIOEvent();
watcher_->OnFileCanWriteWithoutBlocking(fd);
pump->DidProcessIOEvent();
}
这两个函数定义在文件external/chromium_org/base/message_loop/message_pump_libevent.cc中。
从这里就能够看到,FileDescriptorWatcher类的成员函数OnFileCanWriteWithoutBlocking和OnFileCanReadWithoutBlocking仅仅是简单地将接收到的IO事件通知转发给成员变量watcher_描写叙述的一个Watcher对象处理。在转发前后,它们也会分别调用MessagePumpLibevent类的成员函数WillProcessIOEvent和DidProcessIOEvent通知关联的MessagePumpLibevent对象将有IO事件被处理以及IO事件已处理完毕。
这里须要注意的一点是,假设一个文件描写叙述符同一时候发生了读事件和写事件。那么如前所述,先处理写事件,再处理读事件。这样就有可能在处理写事件的时候,关联的FileDescriptorWatcher对象的成员变量watcher_指向的Watcher对象被销毁了,因此在处理读事件的时候,须要先推断成员变量watcher_的值是否为NULL。
假设为NULL,那么就意味着它之前指向的Watcher对象被销毁了,于是就不用往下处理了。
以上就是通过MessagePumpLibevent类实现消息循环的原理,它与Android应用程序使用的消息循环的实现原理是一样的,因此这里我们并没有非常深入地对它进行分析,比如没有深入到Libevent内部去分析,有兴趣的同学能够參考前面Android应用程序消息处理机制(Looper、Handler)分析一文。
IO线程的消息循环之所以要通过MessagePumpLibevent类来实现消息循环,是由于它的消息循环主要是用来监控一个负责运行IPC的UNIX Socket的。也就是说,Chromium的IPC是通过UNIX Socket进行的。
这样当一个进程向另外一个进程发送消息时,就会触发使用的UNIX Socket发生IO事件,然后就会被IO线程的消息循环监控到,最后就能够得到处理。
至此,关于Chromium的线程消息循环我们就分析完毕。可是关于消息发送,还有一些特性值得进一步分析,主要是关于消息的发送接口的。
前面我们分析消息发送接口都是通过MessageLoop提供的。
也就是说,在往一个线程的消息队列发送消息之前,我们首先要获得这个线程的消息循环。这是通过调用Thread类的成员函数message_loop获得的。例如以下所看到的:
class BASE_EXPORT Thread : PlatformThread::Delegate {
public:
......
MessageLoop* message_loop() const { return message_loop_; }
......
};
这个函数定义在文件external/chromium_org/base/threading/thread.h中。
通过调用Thread类的成员函数message_loop直接获取线程的关联的MessageLoop对象会有一个问题,我们以后通过该MessageLoop对象发送消息时,不能保证该MessageLoop对象是有效的,由于线程有可能退出了,这会导致其关联的MessageLoop对象被销毁了。
因此,我们须要有一种机制。即使是线程退出了。我们也能够继续持有一个消息发送接口。
该消息发送接口能够保证。假设线程还没有退出,那么就能正常地向它发送消息。还有一方面,假设线程已经退出。那么最多就是运行一空操作。可是不会造成非法内存訪问。
学习过Chromium和WebKit的智能指针实现原理分析这篇文章之后,我们非常easy想到,能够通过scoped_refptr智能指针来实现这样的机制。Thread类提供了一个成员函数message_loop_proxy。能够获得线程的一个消息发送代理接口,即一个MessageLoopProxy接口。例如以下所看到的:
class BASE_EXPORT Thread : PlatformThread::Delegate {
public:
......
scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
return message_loop_ ?
message_loop_->message_loop_proxy() : NULL; } ...... };
这个函数定义在文件external/chromium_org/base/threading/thread.h中。
这个MessageLoopProxy接口通过scoped_refptr智能指针引用,因此就能保证它还在使用的时候,不会被销毁,即使线程已经退出,这样就能够避免非法内存訪问。
接下来我们就继续分析MessageLoopProxy接口是怎样实现的。
从Thread类的成员函数message_loop_proxy能够知道,它返回给调用者的MessageLoopProxy接口是通过成员变量message_loop_指向的一个MessageLoop对象的成员函数message_loop_proxy获得的。
MessageLoop类的成员函数message_loop_proxy的实现例如以下所看到的:
class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
public:
......
scoped_refptr<MessageLoopProxy> message_loop_proxy() {
return message_loop_proxy_;
}
......
private:
......
scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
......
};
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.h中。
MessageLoop类的成员函数message_loop_proxy返回的是成员变量message_loop_proxy_指向的一个MessageLoopProxyImpl对象。
从前面的分析能够知道,这个成员变量是在MessageLoop类的成员函数Init中初始化的,例如以下所看到的:
void MessageLoop::Init() {
......
incoming_task_queue_ = new internal::IncomingTaskQueue(this);
message_loop_proxy_ =
new internal::MessageLoopProxyImpl(incoming_task_queue_);
......
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数Init首先创建了一个用来描写叙述线程消息队列的一个IncomingTaskQueue,然后再依据这个IncomingTaskQueue创建了一个MessageLoopProxyImpl对象,而且保存在成员变量message_loop_proxy_中。
MessageLoopProxyImpl对象的创建步骤例如以下所看到的:
MessageLoopProxyImpl::MessageLoopProxyImpl(
scoped_refptr<IncomingTaskQueue> incoming_queue)
: incoming_queue_(incoming_queue),
valid_thread_id_(PlatformThread::CurrentId()) {
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop_proxy_impl.cc中。
MessageLoopProxyImpl类的构造函数主要就是将參数incoming_queue指向的一个IncomingTaskQueue对象保存在成员变量incoming_queue_中。
注意。MessageLoopProxyImpl类的成员变量incoming_queue_是一个scoped_refptr智能指针。因此即使它所属的线程退出了,它所引用的IncomingTaskQueue对象仍然是存在的。
MessageLoopProxyImpl类的继承关系如图4所看到的:
从图4能够看到。MessageLoopProxyImpl类从TaskRunner类一路继承下来。TaskRunner类定义了PostTask和PostDelayedTask两个接口。此外,SequencedTaskRunner类又定义了PostNonNestableTask和PostNonNestableDelayedTask两个接口。MessageLoopProxyImpl类本身重写了父类TaskRunner的PostDelayedTask接口以及SequencedTaskRunner类的PostNonNestableDelayedTask接口。这样就使得MessageLoopProxyImpl类像MessageLoop类一样,具有PostTask、PostDelayedTask、PostNonNestableTask和PostNonNestableDelayedTask四个消息发送接口。
TaskRunner类的成员函数PostTask的实现例如以下所看到的:
bool TaskRunner::PostTask(const tracked_objects::Location& from_here,
const Closure& task) {
return PostDelayedTask(from_here, task, base::TimeDelta());
}
这个函数定义在文件external/chromium_org/base/task_runner.cc中。
从这里就能够看到,TaskRunner类的成员函数PostTask终于通过调用由子类MessageLoopProxyImpl重写的接口PostDelayedTask来向线程的消息队列发送消息。
SequencedTaskRunner类的成员函数PostNonNestableTask的实现例如以下所看到的:
bool SequencedTaskRunner::PostNonNestableTask(
const tracked_objects::Location& from_here,
const Closure& task) {
return PostNonNestableDelayedTask(from_here, task, base::TimeDelta());
}
这个函数定义在文件external/chromium_org/base/sequenced_task_runner.cc中。
从这里也能够看到,SequencedTaskRunner类的成员函数PostNonNestableTask终于通过调用由子类MessageLoopProxyImpl重写的接口PostNonNestableDelayedTask来向线程的消息队列发送消息。
因此,不管我们调用MessageLoopProxyImpl类的哪一个消息发送接口,终于都归结为调用PostDelayedTask和PostNonNestableDelayedTask这两个接口,它们的实现例如以下所看到的:
bool MessageLoopProxyImpl::PostDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
DCHECK(!task.is_null()) << from_here.ToString();
return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
}
bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
DCHECK(!task.is_null()) << from_here.ToString();
return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
}
这两个函数定义在文件external/chromium_org/base/message_loop/message_loop_proxy_impl.cc中。
MessageLoopProxyImpl类的成员函数PostDelayedTask和PostNonNestableDelayedTask都是通过调用成员变量imcoming_queue_指向的一个IncomingTaskQueue对象的成员函数AddToIncomingQueue向线程的消息队列发送消息。
从前面的分析能够知道。IncomingTaskQueue类的成员函数AddToIncomingQueue终于调用了另外一个成员函数PostPendingTask向线程的消息队列发送消息。例如以下所看到的:
bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
......
// This should only be called while the lock is taken.
incoming_queue_lock_.AssertAcquired();
if (!message_loop_) {
pending_task->task.Reset();
return false;
}
......
bool was_empty = incoming_queue_.empty();
incoming_queue_.push(*pending_task);
pending_task->task.Reset();
// Wake up the pump.
message_loop_->ScheduleWork(was_empty);
return true;
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
我们注意到,IncomingTaskQueue类的成员函数PostPendingTask在将消息加入到线程的消息队列之前。首先会推断线程的消息循环是否还存在,即推断成员变量message_loop_的值是否等于NULL。假设等于NULL,那么就说明线程已经退出了。这时候就什么也不做就返回了。
IncomingTaskQueue类的成员变量message_loop_是在构造函数中初始化的,例如以下所看到的:
IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
: message_loop_(message_loop),
...... {
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
如今的重点问题就是,IncomingTaskQueue类的成员变量message_loop_是什么时候被设置为NULL的呢?也就是它是怎么知道线程退出的呢?
当线程退出时,MessageLoop对象会被销毁,这时候它的析构函数会被调用,例如以下所看到的:
MessageLoop::~MessageLoop() {
......
// Tell the incoming queue that we are dying.
incoming_task_queue_->WillDestroyCurrentMessageLoop();
......
}
这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的析构函数会调用成员变量incoming_task_queue_指向的一个IncomingTaskQueue对象的成员函数WillDestroyCurrentMessageLoop通知它线程的消息循环要被销毁了。
IncomingTaskQueue类的成员函数WillDestroyCurrentMessageLoop的实现例如以下所看到的:
void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
......
AutoLock lock(incoming_queue_lock_);
message_loop_ = NULL;
}
这个函数定义在文件external/chromium_org/base/message_loop/incoming_task_queue.cc中。
这时候IncomingTaskQueue类的成员变量message_loop_就会被设置为NULL,这样以后再调用IncomingTaskQueue类的成员函数AddToIncomingQueue就再无法向线程的消息队列发送消息了。
从图4还能够看到。我们除了能够使用MessageLoopProxy接口向线程的消息队列发送消息之外,还能够通过SingleThreadTaskRunner、SequencedTaskRunner和TaskRunner接口向线程的消息队列发送消息。这一类接口统称为TaskRunner接口。
TaskRunner是一个用来运行异步任务接口。我们通过它的成员函数PostTask和PostDelayedTask等能够将一个Closure发送给一个线程或者一个线程池运行。由于TaskRunner可能会将不同的Closure交给不同的线程运行。因此不能保证交给它的Closure的运行顺序。
TaskRunner唯一能保证的是它不会同步运行交给它的Closure。也就是不会直接调用Closure的成员函数Run。
SequencedTaskRunner是从TaskRunner继承下来的,可是它比TaskRunner多出一个额外的保证,就是交给它的Closure是依照一定顺序运行的,不会出现两个Closure同一时候运行的情况。比如,给出两个Closure1和Closure2,假设满足下面三个条件,则能保证Closure2在Closure1之后运行:
1. Closure1比Closure2先Post给SequencedTaskRunner;
2. Closure1指定的运行时间点小于等于Closure2指定的运行时间点;
3. Closure1可嵌套消息循环中运行或者Closure2不可嵌套消息循环中运行。
保证Closure2在Closure1之后运行,是说Closure1运行完毕之后,才运行Closure2。而不仅仅是说Closure1的開始运行时间点比Closure2的開始运行时间点早。
SingleThreadTaskRunner是从SequencedTaskRunner继承下来的,可是它比SequencedTaskRunner又多出一个额外的保证,就是交给它的Closure都是由同一个线程运行的,不会出现一个Closure是在一个线程运行,还有一个Closure是在另外一个线程运行的情况。
我们发现一个带消息循环的线程全然能够满足SingleThreadTaskRunner接口的要求。那么我们怎样获得一个线程的SingleThreadTaskRunner接口呢?
MessageLoop类有一个成员变量thread_task_runner_handle_,例如以下所看到的:
class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
......
private:
......
scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
......
};
这个成员变量定义在文件external/chromium_org/base/message_loop/message_loop.h中。
MessageLoop类的成员变量thread_task_runner_handle_是在前面我们分析过的MessageLoop类的成员函数Init初始化的,例如以下所看到的:
void MessageLoop::Init() {
......
incoming_task_queue_ = new internal::IncomingTaskQueue(this);
message_loop_proxy_ =
new internal::MessageLoopProxyImpl(incoming_task_queue_);
thread_task_runner_handle_.reset(
new ThreadTaskRunnerHandle(message_loop_proxy_));
}
这个成员变量定义在文件external/chromium_org/base/message_loop/message_loop.cc中。
MessageLoop类的成员函数Init依据前面创建出来的MessageLoopProxyImpl对象创建了一个ThreadTaskRunnerHandle对象。
一个ThreadTaskRunnerHandle对象的创建步骤例如以下所看到的:
base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
......
ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
const scoped_refptr<SingleThreadTaskRunner>& task_runner)
: task_runner_(task_runner) {
......
lazy_tls_ptr.Pointer()->Set(this);
}
这个函数定义在文件external/chromium_org/base/thread_task_runner_handle.cc中。
从图4能够知道。MessageLoopProxyImpl类是从SingleThreadTaskRunner类继承下来的,因此ThreadTaskRunnerHandle类的构造函数能够接受一个MessageLoopProxyImpl对象作为參数。
ThreadTaskRunnerHandle类的构造函数做了两件事情。第一件事情就是将參数task_runner描写叙述的一个SingleThreadTaskRunner对象保存在成员变量task_runner_中。第二件事情就是将正在创建的ThreadTaskRunnerHandle对象保存线程局部存储变量lazy_tls_ptr中。
ThreadTaskRunnerHandle类还提供了一个静态成员函数Get,用来获得保存在线程局部存储变量lazy_tls_ptr的一个ThreadTaskRunnerHandle对象的成员变量task_runner_描写叙述的一个SingleThreadTaskRunner对象,例如以下所看到的:
scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
ThreadTaskRunnerHandle* current = lazy_tls_ptr.Pointer()->Get();
......
return current->task_runner_;
}
这个函数定义在文件external/chromium_org/base/thread_task_runner_handle.cc中。
这样我们就能够获得一个带消息循环的线程的SingleThreadTaskRunner接口了,这个接口指向的实际上是一个MessageLoopProxyImpl对象,因此终于实际上是通过前面分析的MessageLoopProxyImpl接口来往线程发送消息。
从图4还能够知道,TaskRunner接口提供了一个成员函数PostTaskAndReply,例如以下所看到的:
class BASE_EXPORT TaskRunner
: public RefCountedThreadSafe<TaskRunner, TaskRunnerTraits> {
public:
......
bool PostTaskAndReply(const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply);
......
};
这个函数声明在文件external/chromium_org/base/task_runner.h中。
从TaskRunner类的成员函数PostTaskAndReply的声明能够推断出,它用来向一个目标线程请求异步运行一个任务task。而且当该任务运行完毕时,向发出请求的线程发送一个reply。
它实现的功能正好就是我们在前面图1所描写叙述的线程双向异步通信机制。
接下来我们就分析它是怎样实现的。
TaskRunner类的成员函数PostTaskAndReply的实现例如以下所看到的:
bool TaskRunner::PostTaskAndReply(
const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply) {
return PostTaskAndReplyTaskRunner(this).PostTaskAndReply(
from_here, task, reply);
}
这个函数定义在文件external/chromium_org/base/task_runner.cc中。
TaskRunner类的成员函数PostTaskAndReply首先创建了一个PostTaskAndReplyTaskRunner对象。接着调用这个PostTaskAndReplyTaskRunner对象的成员函数 PostTaskAndReply来实现双向异步通信机制。
PostTaskAndReplyTaskRunner对象的创建步骤例如以下所看到的:
PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner(
TaskRunner* destination) : destination_(destination) {
DCHECK(destination_);
这个函数定义在文件external/chromium_org/base/task_runner.cc中。
PostTaskAndReplyTaskRunner类的构造函数将參数destination描写叙述的一个TaskRunner对象保存在成员变量destination_中。
PostTaskAndReplyTaskRunner类是从PostTaskAndReplyImpl类继承下来的,而且它的成员函数PostTaskAndReply也是从PostTaskAndReplyImpl类继承下来的,因此前面调用PostTaskAndReplyTaskRunner类的成员函数PostTaskAndReply实际上调用的是PostTaskAndReplyImpl类的成员函数PostTaskAndReply。
PostTaskAndReplyImpl类的成员函数PostTaskAndReply的实现例如以下所看到的:
bool PostTaskAndReplyImpl::PostTaskAndReply(
const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply) {
PostTaskAndReplyRelay* relay =
new PostTaskAndReplyRelay(from_here, task, reply);
if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
Unretained(relay)))) {
delete relay;
return false;
}
return true;
}
这个函数定义在文件external/chromium_org/base/threading/post_task_and_reply_impl.cc中。
PostTaskAndReplyImpl类的成员函数PostTaskAndReply先将參数from_here、task和reply封装在一个PostTaskAndReplyRelay对象中。然后再将调用函数Bind创建一个Closure,而且通过调用由子类PostTaskAndReplyTaskRunner实现的成员函数PostTask运行该Closure。注意,这个Closure绑定的是PostTaskAndReplyRelay类的成员函数Run。
PostTaskAndReplyRelay对象的创建步骤例如以下所看到的:
class PostTaskAndReplyRelay {
public:
PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
const Closure& task, const Closure& reply)
: from_here_(from_here),
origin_loop_(ThreadTaskRunnerHandle::Get()) {
task_ = task;
reply_ = reply;
}
......
private:
tracked_objects::Location from_here_;
scoped_refptr<SingleThreadTaskRunner> origin_loop_;
Closure reply_;
Closure task_;
};
这个函数定义在文件external/chromium_org/base/threading/post_task_and_reply_impl.cc中。
PostTaskAndReplyRelay类的构造函数主要就是将參数from_here、task和reply描写叙述的对象分别保存在成员变量from_here_、task_和reply_中。另外,它还会通过我们前面分析过的ThreadTaskRunnerHandle类的静态成员函数Get获得一个SingleThreadTaskRunner对象。而且保存在成员变量origin_loop_中。
注意,这个SingleThreadTaskRunner对象是从当前线程获得的,也就是调用了TaskRunner类的成员函数PostTaskAndReply的线程。
PostTaskAndReplyTaskRunner类的成员函数PostTask的实现例如以下所看到的:
bool PostTaskAndReplyTaskRunner::PostTask(
const tracked_objects::Location& from_here,
const Closure& task) {
return destination_->PostTask(from_here, task);
}
这个函数定义在文件external/chromium_org/base/task_runner.cc中。
从前面的分析能够知道,PostTaskAndReplyTaskRunner类的成员变量destination_指向的一个TaskRunner接口。
假设这个TaskRunner接口描写叙述的是一个从带消息循环的线程的获得的MessageLoopProxyImpl对象,那么PostTaskAndReplyTaskRunner类的成员函数PostTask就是通过该MessageLoopProxyImpl对象向线程的消息队列发送參数task描写叙述的一个消息。
由于參数task指向的是一个Closure对象。而且它绑定的是PostTaskAndReplyRelay类的成员函数Run。因此当上述消息被处理时,PostTaskAndReplyRelay类的成员函数Run就会被调用。
PostTaskAndReplyRelay类的成员函数Run的实现例如以下所看到的:
class PostTaskAndReplyRelay {
public:
......
void Run() {
task_.Run();
origin_loop_->PostTask(
from_here_,
Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
base::Unretained(this)));
}
......
}
这个函数定义在文件external/chromium_org/base/threading/post_task_and_reply_impl.cc中。
PostTaskAndReplyRelay类的成员函数Run调用了成员变量task_指向的一个Closure对象的成员函数Run。从前面的分析能够知道。该Closure对象就是最初调用TaskRunner类的成员函数PostTaskAndReply所要运行的Task。
运行完毕成员变量task_指向的一个Closure之后,接下来PostTaskAndReplyRelay类的成员函数Run接下来向最初调用了TaskRunner类的成员函数PostTaskAndReply的线程发送一个Closure,该Closure绑定的是当前正在处理的PostTaskAndReplyRelay对象的成员函数RunReplyAndSelfDestruct。
PostTaskAndReplyRelay类的成员函数RunReplyAndSelfDestruct的实现例如以下所看到的:
class PostTaskAndReplyRelay {
......
private:
void RunReplyAndSelfDestruct() {
DCHECK(origin_loop_->BelongsToCurrentThread());
// Force |task_| to be released before |reply_| is to ensure that no one
// accidentally depends on |task_| keeping one of its arguments alive while
// |reply_| is executing.
task_.Reset();
reply_.Run();
// Cue mission impossible theme.
delete this;
}
......
}
这个函数定义在文件external/chromium_org/base/threading/post_task_and_reply_impl.cc中。
PostTaskAndReplyRelay类的成员函数RunReplyAndSelfDestruct所做的事情就是在最初调用了TaskRunner类的成员函数PostTaskAndReply的线程中运行成员变量reply_描写叙述的一个Closure对象。从前面的分析能够知道。该Closure对象就是最初用TaskRunner类的成员函数PostTaskAndReply时指定的第三个參数reply所描写叙述的Closure对象。
最后,PostTaskAndReplyRelay类的成员函数RunReplyAndSelfDestruct将当前正在处理的PostTaskAndReplyRelay对象销毁掉。这样,一个双向的异步通信就运行完毕了。
至此。我们就分析完毕Chromium的线程消息循环和消息发送机制了。Chromium的多线程模型正是基于这样的线程消息循环和消息发送机制设计和实现的,其最大的特点是一切皆异步通信,从而提高各个线程,特别是UI线程的响应性,从而让用户觉得Chromium载入网页的速度非常快。
最后,我们分别对Chromium在Android平台实现的线程消息循环和消息发送作一个简要的总结。
Chromium的线程消息循环依据不同的线程具有不同的实现。详细来说,就是:
1. UI线程和Java线程的消息循环是通过Java层的消息循环实现的,也就是通过Android应用程序使用的消息循环实现的。
2. IO线程的消息循环是基于Libevent实现的,也就是通过epoll实现的。这是由于IO线程主要是用来运行IPC,而这样的IPC是通过UNIX Socket实现的。这意味IO线程的消息循环主要用来监控UNIX Socket文件描写叙述符的,因此就适合使用epoll来实现。
3. 其他类型的线程的消息循环是基于条件变量实现的。
Chromium的线程消息发送能够通过下面三种接口实现:
1. SingleThreadTaskRunner、SequencedTaskRunner和TaskRunner。这三个接口是比MessageLoopProxy和MessageLoop更一般的接口,由于它们不关心负责处理消息的线程是怎样实现的。
2. MessageLoopProxy。这个接口比MessageLoop更好用,由于消息的发送者能够一直持有该接口。而不用关心该接口所关联的线程是否已经退出。
3. MessageLoop,这个接口要求使用者确保它所关联的线程是否已经退出,假设已经退出,那么是不能够使用的。
理解Chromium的线程消息循环和消息发送机制对理解Chromium的多线程模型非常重要。而在Chromium的源代码里大量地使用了这些消息循环和消息处理机制。
比如,我们接下来的文章中分析的Chromium多进程通信机制就是通过上面提到的IO线程实现的。敬请关注!很多其他的信息也能够关注老罗的新浪微博:http://weibo.com/shengyangluo。