主要是自己做个学习笔记吧,我经验也不是很丰富,以前学习多线程的时候就感觉写多线程程序很麻烦。主要是线程之间要通信,要切线程,要同步,各种麻烦。我本身的工作经历决定了也没有太多的工作经验,所以chrome的messageloop可以说是我用到的第一个成熟的线程消息封装库,用的很简单,舒服。主要涉及MessageLoop和MessagePump这两个类系。

以前不太清楚chrome当时在设计这两个类时是如何分工的,今天又看了一下代码,有了点感觉。MessagePump主要用来做消息循环, 与操作系统等平台相关的部分都在MessagePump类里, 针对不同的平台有不同的实现,对messageloop封装了平台的不一致性。而MessageLoop主要是处理chrome自己的task机制的,这一部分。我们以windows平台来进行代码分析, MessagePump中的DoRunLoop是每个线程进行消息循环处理的地方。

void MessagePumpForUI::DoRunLoop() {

  for (;;) {
// If we do any work, we may create more messages etc., and more work may
// possibly be waiting in another task group. When we (for example)
// ProcessNextWindowsMessage(), there is a good chance there are still more
// messages waiting. On the other hand, when any of these methods return
// having done no work, then it is pretty unlikely that calling them again
// quickly will find any work to do. Finally, if they all say they had no
// work, then it is a good time to consider sleeping (waiting) for more
// work. bool more_work_is_plausible = ProcessNextWindowsMessage();
if (state_->should_quit)
break; more_work_is_plausible |= state_->delegate->DoWork();
if (state_->should_quit)
break; more_work_is_plausible |=
state_->delegate->DoDelayedWork(&delayed_work_time_);
// If we did not process any delayed work, then we can assume that our
// existing WM_TIMER if any will fire when delayed work should run. We
// don't want to disturb that timer if it is already in flight. However,
// if we did do all remaining delayed work, then lets kill the WM_TIMER.
if (more_work_is_plausible && delayed_work_time_.is_null())
KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
if (state_->should_quit)
break; if (more_work_is_plausible)
continue; more_work_is_plausible = state_->delegate->DoIdleWork();
if (state_->should_quit)
break; if (more_work_is_plausible)
continue; WaitForWork(); // Wait (sleep) until we have work to do again.
}
}

这块儿代码通过一个for的死循环来维持线程的运行, 同时进行系统消息的处理和task的处理,从代码看可以分为循环可以分为如下几个部分:伪码描述:

for(;;)
{
处理windows系统消息 执行task队列中的一个task 执行delayedTask队列中的一个task。 if(还有其他任务(more_work_is_pausiable)),
continue;
else
挂起线程,等待消息进行唤醒
}

下面分别从几部分进行分析:

处理windows消息

循环先从Windows的消息队列中提取下一条消息进行处理。

bool more_work_is_plausible = ProcessNextWindowsMessage();
bool MessagePumpForUI::ProcessNextWindowsMessage() {
// If there are sent messages in the queue then PeekMessage internally
// dispatches the message and returns false. We return true in this
// case to ensure that the message loop peeks again instead of calling
// MsgWaitForMultipleObjectsEx again.
bool sent_messages_in_queue = false;
DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
if (HIWORD(queue_status) & QS_SENDMESSAGE)
sent_messages_in_queue = true; MSG msg;
if (message_filter_->DoPeekMessage(&msg, NULL, , , PM_REMOVE))
return ProcessMessageHelper(msg); return sent_messages_in_queue;
}

在processNextWindowsMessage函数中主要处理 window的窗口消息,它的返回值 表示输入队列中是否还有其他消息待处理,这样可以避免多调用一次MsgWaitForMultipleObjectsEx。

具体的ProcessMessageHelper代码如下,单独的WM_QUIT来进行单独推出处理。

bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
"message", msg.message);
if (WM_QUIT == msg.message) {
state_->should_quit = true;
PostQuitMessage(static_cast<int>(msg.wParam));
return false;
} // While running our main message pump, we discard kMsgHaveWork messages.
if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
return ProcessPumpReplacementMessage(); if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
return true; WillProcessMessage(msg); if (!message_filter_->ProcessMessage(msg)) {
if (state_->dispatcher) {
if (!state_->dispatcher->Dispatch(msg))
state_->should_quit = true;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} DidProcessMessage(msg);
return true;
}

执行task

处理了一个windows消息后, 然后通过MessagePump::Delegate的接口,调用MessageLoop的DoWork操作,来处理task队列。

 more_work_is_plausible |= state_->delegate->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;
}

这个函数中通过循环来找到一个处理当前taskQueue的一个task进行执行, 将delayed的task 存入DelayedWorkQueue.

执行DelayedTask

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;
} // When we "fall behind," there will be a lot of tasks in the delayed work
// queue that are ready to run. To increase efficiency when we fall behind,
// we will only call Time::Now() intermittently, and then process all tasks
// that are ready to run before calling it again. As a result, the more we
// fall behind (and have a lot of ready-to-run delayed tasks), the more
// efficient we'll be at handling the tasks. 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);
}

比对时间,如果到了delayedtask的执行时机,执行delayed task。

挂起等待用户输入消息

void MessagePumpForUI::WaitForWork() {
// Wait until a message is available, up to the time needed by the timer
// manager to fire the next set of timers.
int delay = GetCurrentDelay();
if (delay < 0) // Negative value means no timers waiting.
delay = INFINITE; DWORD result;
result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
MWMO_INPUTAVAILABLE); if (WAIT_OBJECT_0 == result) {
// A WM_* message is available.
// If a parent child relationship exists between windows across threads
// then their thread inputs are implicitly attached.
// This causes the MsgWaitForMultipleObjectsEx API to return indicating
// that messages are ready for processing (Specifically, mouse messages
// intended for the child window may appear if the child window has
// capture).
// The subsequent PeekMessages call may fail to return any messages thus
// causing us to enter a tight loop at times.
// The WaitMessage call below is a workaround to give the child window
// some time to process its input messages.
MSG msg = {0};
DWORD queue_status = GetQueueStatus(QS_MOUSE);
if (HIWORD(queue_status) & QS_MOUSE &&
!PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
WaitMessage();
}
return;
} DCHECK_NE(WAIT_FAILED, result) << GetLastError();
}

  通过MsgWaitForMultiPleObjectsEx来进行挂起等待。

语言表达能力不行,不知到说清楚没有 。 不清楚在补吧

Chrome中的消息循环的更多相关文章

  1. TMsgThread, TCommThread -- 在delphi线程中实现消息循环

    http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...

  2. TMsgThread, TCommThread -- 在delphi线程中实现消息循环(105篇博客,好多研究消息的文章)

    在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使用很方便,但是有时候我们需要在线程类中使用消息循环,delphi没有提供.   花了两天的事件研究了 ...

  3. 安卓中的消息循环机制Handler及Looper详解

    我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handl ...

  4. Looper.loop() android线程中的消息循环

    Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建一个消息循环,调用Loope ...

  5. Windows 消息循环(2) - WPF中的消息循环

    接上文: Windows 消息循环(1) - 概览 win32/MFC/WinForm/WPF 都依靠消息循环驱动,让程序跑起来. 本文介绍 WPF 中是如何使用消息循环来驱动程序的. 4 消息循环在 ...

  6. TCommThread -- 在delphi线程中实现消息循环

    http://www.techques.com/question/1-4073197/How-do-I-send-and-handle-message-between-TService-parent- ...

  7. Android应用程序线程消息循环模型分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是 ...

  8. 深入探讨MFC消息循环和消息泵

    首先,应该清楚MFC的消息循环(::GetMessage,::PeekMessage),消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情.在MFC ...

  9. Android消息循环分析

    我们的经常使用的系统中,程序的工作一般是有事件驱动和消息驱动两种方式,在Android系统中,Java应用程序是靠消息驱动来工作的. 消息驱动的原理就是: 1. 有一个消息队列.能够往这个队列中投递消 ...

随机推荐

  1. SQL Server 2012 BI 学习 第一天

    了解数据源,数据源视图,多维数据集,维度 数据源:一个数据库或者其它数据链接,SSAS不支持使用模拟功能来处理 OLAP 对象.模拟信息选择“使用服务帐户” 数据源视图:DSV是元数据的单个统一视图, ...

  2. 客户端访问WebService和PageMethod

    客户端访问WebService 客户端访问WebService和后台访问WebService没什么不同,注意的地方是要在ScriptManager中添加 <Services>        ...

  3. cadence 机械孔的制作

    在平时画PCB的时候,会用到安装孔,好多人就是找个过孔,在原理图中连接GND,这样使用也可以,下面介绍一种正经机械孔的制作方法(自己摸索的),制作一个孔径为3mm的安装孔. 1 打开pad desig ...

  4. java之jar命令详解

    1. JAR 文件包 JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种文档格式.JAR 文件非常类似 ZIP 文件——准确的说, ...

  5. myeclipse配置下tomcat debug启动很无比慢

    myeclipse配置下tomcat debug启动很无比慢,而run启动很快今天照常使用MyEclipse 6.5 Blue Edition进行开发,但是却遇到一个怪问题.在MyEclipse环境下 ...

  6. php操作mysqli(示例代码)

    <?php define("MYSQL_OPEN_LOGS",true); class mysqliHelp { private $db; public function _ ...

  7. js SVG

    Snap.svg Paths.js http://www.sitepoint.com/creating-animated-valentines-day-card-snap-svg/

  8. cocos2dx中的动作

    CCAction是cocos2dx中专门用来处理动作相关的类,几乎所有的与动作相关的类都是从它派生而来的.而CCAction继承自CCObject class CCFiniteTimeAction : ...

  9. vs2013中头文件中大小写的切换的快捷键

    1.选中内容 2.ctrl+shift+u 例如:  #include "LayerStart.h"   ->   #include "LAYERSTART.H&q ...

  10. clion windows 开发配置

    1.下载clion 并且安装. 地址 : http://download-cf.jetbrains.com/cpp/clion-1.0.1.exe 2.安装cygwin  地址: https://cy ...