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

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

  1. void MessagePumpForUI::DoRunLoop() {
  2.  
  3. for (;;) {
  4. // If we do any work, we may create more messages etc., and more work may
  5. // possibly be waiting in another task group. When we (for example)
  6. // ProcessNextWindowsMessage(), there is a good chance there are still more
  7. // messages waiting. On the other hand, when any of these methods return
  8. // having done no work, then it is pretty unlikely that calling them again
  9. // quickly will find any work to do. Finally, if they all say they had no
  10. // work, then it is a good time to consider sleeping (waiting) for more
  11. // work.
  12.  
  13. bool more_work_is_plausible = ProcessNextWindowsMessage();
  14. if (state_->should_quit)
  15. break;
  16.  
  17. more_work_is_plausible |= state_->delegate->DoWork();
  18. if (state_->should_quit)
  19. break;
  20.  
  21. more_work_is_plausible |=
  22. state_->delegate->DoDelayedWork(&delayed_work_time_);
  23. // If we did not process any delayed work, then we can assume that our
  24. // existing WM_TIMER if any will fire when delayed work should run. We
  25. // don't want to disturb that timer if it is already in flight. However,
  26. // if we did do all remaining delayed work, then lets kill the WM_TIMER.
  27. if (more_work_is_plausible && delayed_work_time_.is_null())
  28. KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
  29. if (state_->should_quit)
  30. break;
  31.  
  32. if (more_work_is_plausible)
  33. continue;
  34.  
  35. more_work_is_plausible = state_->delegate->DoIdleWork();
  36. if (state_->should_quit)
  37. break;
  38.  
  39. if (more_work_is_plausible)
  40. continue;
  41.  
  42. WaitForWork(); // Wait (sleep) until we have work to do again.
  43. }
  44. }

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

  1. for(;;)
  2. {
  3. 处理windows系统消息
  4.  
  5. 执行task队列中的一个task
  6.  
  7. 执行delayedTask队列中的一个task
  8.  
  9. if(还有其他任务(more_work_is_pausiable)),
  10. continue;
  11. else
  12. 挂起线程,等待消息进行唤醒
  13. }

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

处理windows消息

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

  1. bool more_work_is_plausible = ProcessNextWindowsMessage();
  1. bool MessagePumpForUI::ProcessNextWindowsMessage() {
  2. // If there are sent messages in the queue then PeekMessage internally
  3. // dispatches the message and returns false. We return true in this
  4. // case to ensure that the message loop peeks again instead of calling
  5. // MsgWaitForMultipleObjectsEx again.
  6. bool sent_messages_in_queue = false;
  7. DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
  8. if (HIWORD(queue_status) & QS_SENDMESSAGE)
  9. sent_messages_in_queue = true;
  10.  
  11. MSG msg;
  12. if (message_filter_->DoPeekMessage(&msg, NULL, , , PM_REMOVE))
  13. return ProcessMessageHelper(msg);
  14.  
  15. return sent_messages_in_queue;
  16. }

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

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

  1. bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
  2. TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
  3. "message", msg.message);
  4. if (WM_QUIT == msg.message) {
  5. state_->should_quit = true;
  6. PostQuitMessage(static_cast<int>(msg.wParam));
  7. return false;
  8. }
  9.  
  10. // While running our main message pump, we discard kMsgHaveWork messages.
  11. if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
  12. return ProcessPumpReplacementMessage();
  13.  
  14. if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
  15. return true;
  16.  
  17. WillProcessMessage(msg);
  18.  
  19. if (!message_filter_->ProcessMessage(msg)) {
  20. if (state_->dispatcher) {
  21. if (!state_->dispatcher->Dispatch(msg))
  22. state_->should_quit = true;
  23. } else {
  24. TranslateMessage(&msg);
  25. DispatchMessage(&msg);
  26. }
  27. }
  28.  
  29. DidProcessMessage(msg);
  30. return true;
  31. }

执行task

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

  1. more_work_is_plausible |= state_->delegate->DoWork(); 
  1. bool MessageLoop::DoWork() {
  2. if (!nestable_tasks_allowed_) {
  3. // Task can't be executed right now.
  4. return false;
  5. }
  6.  
  7. for (;;) {
  8. ReloadWorkQueue();
  9. if (work_queue_.empty())
  10. break;
  11.  
  12. // Execute oldest task.
  13. do {
  14. PendingTask pending_task = work_queue_.front();
  15. work_queue_.pop();
  16. if (!pending_task.delayed_run_time.is_null()) {
  17. AddToDelayedWorkQueue(pending_task);
  18. // If we changed the topmost task, then it is time to reschedule.
  19. if (delayed_work_queue_.top().task.Equals(pending_task.task))
  20. pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
  21. } else {
  22. if (DeferOrRunPendingTask(pending_task))
  23. return true;
  24. }
  25. } while (!work_queue_.empty());
  26. }
  27.  
  28. // Nothing happened.
  29. return false;
  30. }

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

执行DelayedTask

  1. bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
  2. if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
  3. recent_time_ = *next_delayed_work_time = TimeTicks();
  4. return false;
  5. }
  6.  
  7. // When we "fall behind," there will be a lot of tasks in the delayed work
  8. // queue that are ready to run. To increase efficiency when we fall behind,
  9. // we will only call Time::Now() intermittently, and then process all tasks
  10. // that are ready to run before calling it again. As a result, the more we
  11. // fall behind (and have a lot of ready-to-run delayed tasks), the more
  12. // efficient we'll be at handling the tasks.
  13.  
  14. TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
  15. if (next_run_time > recent_time_) {
  16. recent_time_ = TimeTicks::Now(); // Get a better view of Now();
  17. if (next_run_time > recent_time_) {
  18. *next_delayed_work_time = next_run_time;
  19. return false;
  20. }
  21. }
  22.  
  23. PendingTask pending_task = delayed_work_queue_.top();
  24. delayed_work_queue_.pop();
  25.  
  26. if (!delayed_work_queue_.empty())
  27. *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
  28.  
  29. return DeferOrRunPendingTask(pending_task);
  30. }

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

挂起等待用户输入消息

  1. void MessagePumpForUI::WaitForWork() {
  2. // Wait until a message is available, up to the time needed by the timer
  3. // manager to fire the next set of timers.
  4. int delay = GetCurrentDelay();
  5. if (delay < 0) // Negative value means no timers waiting.
  6. delay = INFINITE;
  7.  
  8. DWORD result;
  9. result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
  10. MWMO_INPUTAVAILABLE);
  11.  
  12. if (WAIT_OBJECT_0 == result) {
  13. // A WM_* message is available.
  14. // If a parent child relationship exists between windows across threads
  15. // then their thread inputs are implicitly attached.
  16. // This causes the MsgWaitForMultipleObjectsEx API to return indicating
  17. // that messages are ready for processing (Specifically, mouse messages
  18. // intended for the child window may appear if the child window has
  19. // capture).
  20. // The subsequent PeekMessages call may fail to return any messages thus
  21. // causing us to enter a tight loop at times.
  22. // The WaitMessage call below is a workaround to give the child window
  23. // some time to process its input messages.
  24. MSG msg = {0};
  25. DWORD queue_status = GetQueueStatus(QS_MOUSE);
  26. if (HIWORD(queue_status) & QS_MOUSE &&
  27. !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
  28. WaitMessage();
  29. }
  30. return;
  31. }
  32.  
  33. DCHECK_NE(WAIT_FAILED, result) << GetLastError();
  34. }

  通过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. Eclipse导入android包错误

    错误提示:Invalid project description… 解决方案:假设你的工作空间是workshop,那么你可以在你的workshop下新建一个文件夹,然后放入你的包,再在Eclipse中 ...

  2. highchars

    var drawChart = function(sourceUrl) { $.ajax({ "type" : "post", "url" ...

  3. 括弧匹配检验(check)

    /*题目:括弧匹配检验 检验给定表达式中括弧是否正确匹配 (两种括弧“( ) ”“[]" ,正确输出OK,错误则输出wrong. 2016年8月8日07:24:58 作者:冰樱梦 */ # ...

  4. opencv学习笔记(05)——操作相邻区域

    下面的例子以灰度图像为例: #include <opencv2\highgui\highgui.hpp> #include <opencv2\imgproc\imgproc.hpp& ...

  5. TAG的用法和用途[转]

    用一个例子来说明:一个combobox控件...一个textBox控件...一个datagridview控件!datagridview控件是连接数据库的...combobox和textBox是联合查询 ...

  6. Oracle查询出最最近一次的一条记录

    需求:从一个表中查询数据,得到的数据为最新的一条记录. -------------建立测试表 --drop table TB ),dtDate date) -------------插入测试数据 ,' ...

  7. springboot pom 引用集合

    <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</arti ...

  8. hornetq 入门(1)

    Hornetq 版本2.4.0final  需要JDK7及以上 Hornetq官网 Hornetq2.1中文手册 step1.启动服务端 1.1准备配置文件(配置说明参考官网手册) hornetq-c ...

  9. DataGridView 使用CheckBox选中行

    在winform中使用checbox很多.上次那个项目里就用到了,写了一个不太好用,后来翻阅了一下微软提供的样码,我觉得有必要给大家分享一下. // This event handler manual ...

  10. spring中Bean的注入参数详解

    字面值    一般指可用字符串表示的值,这些值可以通过<value>元素标签进行注入.在默认情况下,基本数据类型及其封装类.String等类型都可以采取字面值注入的方式,Spring容器在 ...