注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

chrome源码解析系列:Chrome消息系统(1)  

2009-12-01 16:19:38|  分类: Chrome |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

chrome中有很多闪光点地方,它的消息系统就一快纯金,要看chrome 源码,必须要过消息系统这关。
   本来这本部打算写在上一章的,考虑内容涵盖范围太广的,打算另开一章来写 chrome的消息系统,回头在去上一章做个比较有概括力的总结。

本章的思路是按照一下逻辑来展开的:
  1:消息系统的概述(消息系统静态模型和动态模型的一个简单的介绍)
  2:一个消息系统的生死因果(细说MessageLoopUI类)
  3:消息系统的分类(对chrome的几种消息做消息介绍)

 

1:消息系统的概述

(1)消息系统的静态结构

这是消息系统的第一个部分,先看看和消息相关的静态类图:

 

(图片画的太大了,这张看的不是很清楚,需要大图片,可以去我的新浪空间去看 大图片)

上面那张图片涉及到设计软件时几种采用的伎俩,下面会一一分析:

 

伎俩一:handle-body,pimpl, 桥接

MessageLoop基本就是MessagePump的一个代理类,

扩充了一些MessagePump没有的功能,

chrome本意可以能是想让Message来处理所有事务,

而这个messgaePump可以做到对调用者透明。

但是对于研究chrome代码的CODER来说,

了解MessagePump是不可推卸的责任。

后面都会详细分析的。

MessagePump和MessageLoop采用用了一种handle-body或称pimpl的伎俩,

按照牛逼点的叫法叫着桥接,

关于此伎俩可以参考四人帮的设计模式。

 

伎俩二:委托

Chrome中已经用烂了改伎俩,基本上所有代码中都能看见此手法。

一个类的内部操作委托给外面的一个对象,通过抽象接口。

如上面代码所示,MessagePump把  DoWork  DoDelayWork, DoIdelWork通过MessagePump::Deletgate 的接口委托给M essageLoop去处理,这样比较好的解决了代码间的耦合问题。

类似伎俩在消息系统这块还有很多:

MessagePump::Watcher           《对应handle的事件处理》

MessagePump::Observer          《监视Windows消息的处理》

MessagePump::Dispatcher         《Windows本地消息的分派》

MessageLoop::DestructionObserver 《用来跟踪MessageLoop的稀构》

这些都是委托的接口,只不过名字不像MessagePump::Deletgate这么张扬而已。

把委托的接口类写到类的内部,

对于chrome这种写法我是我以前没有考虑过的,

是个非常清晰的代码风格,

coder一看就能知道这个委托接口是干吗的。

 

伎俩三:线程本地存储

一个线程怎么获取到当前线程的消息循环对象,通过线程本地存储。

所谓的线程本地存储就是把一个变量和一个线程相关联.

最简单的说是我定义了一个全局的 int n变量,我把n设置为线程本地存储变量,当开启了4个线程,这四个线程都修改了 n这个变量,结果是n对应于每个线程都有一份拷贝,即四个线程四份n的值。

Chrome中是把 MessageLoop对象设置为线程本地存储,

每个线程获取线程的消息循环很简单,直接通过调用MessageLoop一个静态的current()方法返回当前线程的消息循环。

比如在一个线程里面运行一个消息循环

 MessageLoop::current()->Run();
伎俩四:关于chrome 添加任务的方式

注意观察MessageLoop中的任务队列,会发现它有四个队列,如下:

incoming_queue_              《所有任务都是首先添加到该队列中》

work_queue_                   《当前的工作队列》

delayed_work_queue_            《推迟指定时间执行的任务队列》

deferred_non_nestable_work_queue_《不能重入被推迟执行任务队列》

现在要弄明白每个队列的在MesageLoop中的语意,只有先了解了语意才能知道为什么要这样设计。

incoming_queue_ 和 work_queue_  队列的区别?

由于添加队列设计到多线程操作,必然需要对其加锁。

程序的设计原则是能不用锁打死也不用,现在chrome的MessageLoop需要段的加入消息,循环内部需要不断地处理消息,如果每次添加和取消息都要对队列加锁,那么是比会影响其执行效率。

如是,chrome采用了这样的一个措施,采用两个队列:

一个用来从外部线程收集任务的队列(incoming_queue),一个是供内部使用的队列(work_queue),并且保证从work_queue队列中取出任务不需要加锁。

遵循以下三个原则:

1:每次添加一个任务都需要加锁(任务被添加到incoming_queue)

2:每次从work_queue队列中取出任务不需要加锁。

3:在work_queue为空时需要把incoming_queue队列中的内容取出来,取出的操作需要加锁

这样循环的效率可以提高 40-50%。

 

void MessageLoop::ReloadWorkQueue() {
  // We can improve performance of our loading tasks from incoming_queue_ to
  // work_queue_ by waiting until the last minute (work_queue_ is empty) to
  // load.  That reduces the number of locks-per-task significantly when our
  // queues get large.
  if (!work_queue_.empty())
    return;  // Wait till we *really* need to lock and load.

  // Acquire all we can from the inter-thread queue with one lock acquisition.
  {
    AutoLock lock(incoming_queue_lock_);
    if (incoming_queue_.empty())
      return;
    std::swap(incoming_queue_, work_queue_);
    DCHECK(incoming_queue_.empty());
  }
}
关于 delayed_work_queue_  和deferred_non_nestable_work_queue 队列后面再来介绍。

 

 


(2)消息动态流程

和WINDOWS的传统消息机制类似,但是它扩充了WINDOWS的消息循环机制,使得它能够支持事件对象和任务。

 


 

这张图片简单的描述了消息的线程的创建和通讯过程(看大图片)。


       Chrome对自己的线程采取一种lazyCreate 的策略,就是每个线程在需要的时候才被创建。线程之间是通过g_browser_process这个全局对对象来获取相应的线程中的消息循环,然后再通过消息循环中的PostTask 系列的函数来发送任务到相应的线程队列中去。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bzero1982/archive/2008/10/20/3111601.aspx

  评论这张
 
阅读(878)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017