17. 自顶向下的讲吧,从 Thread 类开始。在代码面前,没有 magic,即使是 google 写的也一样。 Thread
类顾名思义就是代表着一个线程对象。继承自 PlatformThread::Delegate,这个 delegate 没什么好说
的 , 规 定 子 类 实 现 一 个 ThreadMain , 这 个 函 数 在 线 程 被 创 建 后 调 用 :
src/base/threading/platform_thread_win.cc 代码:
DWORD __stdcall ThreadFunc(void* params) {
ThreadParams* thread_params = static_cast<ThreadParams*>(params);
PlatformThread::Delegate* delegate = thread_params->delegate;
if (!thread_params->joinable)
base::ThreadRestrictions::SetSingletonAllowed(false);
delete thread_params;
delegate->ThreadMain();
return NULL;
}
// CreateThreadInternal() matches PlatformThread::Create(), except that
// |out_thread_handle| may be NULL, in which case a non-joinable thread is
// created.
bool CreateThreadInternal(size_t stack_size,
PlatformThread::Delegate* delegate,
PlatformThreadHandle* out_thread_handle) {
PlatformThreadHandle thread_handle;
unsigned int flags = 0;
18. if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
} else {
stack_size = 0;
}
ThreadParams* params = new ThreadParams;
params->delegate = delegate;
params->joinable = out_thread_handle != NULL;
// Using CreateThread here vs _beginthreadex makes thread creation a bit
// faster and doesn't require the loader lock to be available. Our code will
// have to work running on CreateThread() threads anyway, since we run
code
// on the Windows thread pool, etc. For some background on the
difference:
// http://www.microsoft.com/msj/1099/win32/win321099.aspx
thread_handle = CreateThread(
NULL, stack_size, ThreadFunc, params, flags, NULL);
if (!thread_handle) {
delete params;
return false;
20. 体原因后面会提到),因为当年也是一开始就读这块的代码,第一次看这三个东西几乎完全不知道他
们是什么关系,到底做什么事情,他们几个接口都很可恶的差不多。接下来我们逐个往下看吧
首先,我们先看看 MessageLoop 类,文件位于 src/base/message_loop.cc, src/base/message_loop.h
这个东西一看就很霸气外露,头文件和 cc 加起来居然有坑爹的 1000 多行,但是请不要被吓着,其实
内 容 真 心 不 多 。 先 看 类 的 定 义 class BASE_EXPORT MessageLoop : public
base::MessagePump::Delegate { … }, 上来就和 MessagePump 扯上了点关系,这个 Delegate 是要
求实现一系列的 DoWork 方法。既然这个 delegate 东西是 messageloop 和 messagepump 的纽带,
我们就看看具体是个什么东西: 代码:
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 {
21. 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;
}
要不怎么说 google 是全世界最牛 b 的互联网公司,这代码写的清清楚楚掷地有声,不需要看懂每个
函数的意义,一看过去就明白了大概的意思:首先尝试从 workqueue 中加载一下 task, 如果为空的话
直接推出循环,否则一个个 task 做,直到没有新的 task 为止(work_queue_.empty() == true)。
22. 当时我看到这段心中大喊坑爹,不对啊,不是说好的 message_loop 嘛,这尼玛也不会永远的 loop
下去嘛,task做完怎么就break了,原来是我先入为主的以为此处实现的是整个消息队列的消息循环,
但是我错了,这个 message_loop 实现的是挨个的做 task, 和维护 task 的等待队列. 真正的 loop 在
message_pump 里! 然后我满怀期待的打开了 message_pump.h,发现 google 为了跨平台,在每
个平台用不同工具实现了各种各样的 messagepump, 在 message_pump.h 中定义的是一个接口,但
是我们找到了 Run()方法的定义!不用说,这个是真正的消息循环,打开 message_pump_default.cc
一看,果不其然华丽丽的标准消息队列死循环出现在我的眼前。 代码:
void MessagePumpDefault::Run(Delegate* delegate) {
DCHECK(keep_running_) << "Quit must have been called outside of Run!";
for (;;) {
mac::ScopedNSAutoreleasePool autorelease_pool;
bool did_work = delegate->DoWork();
if (!keep_running_)
break;
did_work |= delegate->DoDelayedWork(&delayed_work_time_);
if (!keep_running_)
break;
if (did_work)
23. continue;
did_work = delegate->DoIdleWork();
if (!keep_running_)
break;
if (did_work)
continue;
if (delayed_work_time_.is_null()) {
event_.Wait();
} else {
TimeDelta delay = delayed_work_time_ - 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