这篇研究两个问题:chromium对线程的封装和进程通信。主要参考chromium的官方技术文档:TreadingInter-process Communication (IPC)

chrome速度快的优点,主要得益于线程模型的设计,这也是chrome最值得研究的技术点。

 
    一、线程模型
 
    chromium中的线程分为很多种类型,每个线程中有一个MessageLoop处理线程消息,对应实现:
    Thread - base/threading/thread.h
    MessageLoop - base/message_loop.h

    线程的类型包括:io_thread,file_thread,db_thread,safe_browsing_thread等,其中io_thread是一个事件分发线程,管理browser进程和子进程的通信。(上一篇多进程架构图中可以看到它。)
 
    chromium线程设计有一个非常重要的目标:保证UI线程的快速响应,也就是要确保UI线程中没有阻塞的I/O或耗时操作。保证这一点需要一个高效的多线程模型,面临的问题是:
    1、想尽一切办法减少多线程锁;
    2、多线程通信方式。
 
    chromium的实现手段:
    1、线程内消息循环的设计,为线程异步调用打下基础;
    2、Task封装,解决了加锁的问题,同时用command模式统一同步和异步调用。
    也就是说,Task是对一个任务处理的封装,而线程的消息循环都认识Task,这样整个多线程框架其实就是Task的传递和执行的过程,并且锁只在传递Task时发生。多么简单有效的模型!
 
    消息循环
    来看张图(引用自Chrome源码剖析
    

图示将线程的消息循环处理描述的非常清楚,基本思路和windows的消息循环非常相似。

当然,不同类型的线程并不会处理所有的事件,但所有的消息循环都会处理Task。

    线程消息循环分为MessageLoop和MessagePump,其中MessageLoop专门处理Task,而MessagePump处理其他消息,
 
发现Task时交给MessageLoop。不同线程的消息循环的MessageLoop和MessagePump如图:
 

    Task    
    Task是对行为的封装,或者说是将处理函数封装为一个对象。Task对象有一个Run函数,供目标线程的消息循环调用,执行Task的处理。还是看张图:

    如果A线程想让B线程处理一个事务,A只需创建一个Task,将事务处理代码封装好,找到B线程的MessageLoop对象,调用PostTask方法将Task插入消息队列。PostTask将立即返回,A线程继续处理自己的消息循环。B线程消息循环处理到Task时,调用其Run方法完成事务处理。
    chromium对Task的创建和传递做了封装,并定义了丰富的Task类型,满足多种场景需要。同时支持Task自身的日志和统计,便于调试。
    参考文章:
    
    二、进程通信(IPC)
 
    chromium的进程通信在Windows下采用命名管道(在Linux & Mac上采用socketpair),涉及到的进程主要是Browser process、Renderer process和Plugin process。
 
(具体可以参考我的上一篇博文。)实际上最主要的通信发生在Browser和Renderer之间,基本上每一个Renderer process对应一个named pipe与Browser通信。
 
管道通信采用异步模式,保证不会发生阻塞。
 
    根据上一篇博文提到的多进程模型图,可以知道Browser process中有一个I/O线程专门处理IPC,I/O线程和main thread之间通过ChannelProxy传递消息,I/O线程的主要目的是为了处理请求resource等可能阻塞的动作。Renderer process则用其main thread处理进程消息收发。
 
    命名管道根据定义好的规则生成,需要通信的两个进程都认识这个管道,之后就可以按照管道的技术特点通信了。
 
chromium将这些逻辑用IPC::Channel封装,Channel处理三件事情:Send,Listen,处理Watcher,看张图:

    
 
    发送进程调用Channel::Send将消息放到自己某线程的消息队列中,消息循环发现消息的信号量激活则序列化消息写到管道中。
 
操作系统负责将管道内容进行传递并通知接收进程,接收进程有一个I/O类型的线程,其消息循环处理Watcher(参考前面的讲解),
 
当发现Watcher的信号量被激活(收到消息),调用Watcher中对应的OnObjectSignaled方法,该方法通知本进程的Channel去管道中读取数据,并调用Listener解析处理。
 
    chromium用消息循环支撑了进程通信机制,并保证了异步处理防止阻塞。
 
    上面提到的ChannelProxy与Channel是什么关系呢?chromium为了保证线程安全,将Channel设计为由每个进程的I/O线程处理。
 
如果进程中的非I/O线程想发送进程消息怎么办?一个简单思路是将消息发送封装成Task交给I/O线程去处理,chromium将这个处理封装成了ChannelProxy,方便使用。
 
ChannelProxy甚至支持接收到消息后将其返回给原始发送消息的线程。基于以上,Browser的main thread想发送进程消息都必须通过ChannelProxy让I/O thread处理。
    有时需要同步的进程通信,这部分封装在ChannelProxy的子类SyncChannel中。
 
    chromium中的消息有两类:Routed消息和Control消息。简单来说,Routed消息有明确去向,会关联到一个视图上;
 
Control消息不指定到视图,通常被创建管道的class处理。
    chromium为消息和Channel的使用封装了一套宏和模板,来简化进程通信的调用。具体可以参考:Inter-process Communication (IPC)

chromium ②的更多相关文章

  1. QT5利用chromium内核与HTML页面交互

    在QT5.4之前,做QT开发浏览器只能选择QWebkit,但是有过使用的都会发现,这个webkit不是出奇的慢,简直是慢的令人发指,Release模式下还行,debug下你就无语了,但是webkit毕 ...

  2. Google之Chromium浏览器源码学习——base公共通用库(一)

    Google的优秀C++开源项目繁多,其中的Chromium浏览器项目可以说是很具有代表性的,此外还包括其第三开发开源库或是自己的优秀开源库,可以根据需要抽取自己感兴趣的部分.在研究.学习该项目前的时 ...

  3. 如何在windows上编译Chromium (CEF3) 并加入MP3支持(二)

    时隔一年,再次编译cef3,独一无二的目的仍为加入mp3支持.新版本的编译环境和注意事项都已经发生了变化,于是再记录一下. 一.编译版本 cef版本号格式为X.YYYY.A.gHHHHHHH X为主版 ...

  4. 如何在Windows上从源码编译Chromium (CEF3) 加入mp3支持

    一.什么是CEF CEF即Chromium Embeded Framework,由谷歌的开源浏览器项目Chromium扩展而来,可方便地嵌入其它程序中以得到浏览器功能. CEF包括CEF1和CEF3两 ...

  5. 构建基于Chromium的应用程序

    chromium是google chrome浏览器所采用的内核,最开始由苹果的webkit发展而出,由于webkit在发展上存在分歧,而google希望在开发上有更大的自由度,2013年google决 ...

  6. ubuntu中chromium无法播放flash,安装flash

    ubuntu14.0.4中系统自带的chromium无法播放flash,后来查了下,得知chromium已经不支持adobe flash了,用户可使用pepper flash替代.安装pepper f ...

  7. windows下编译chromium浏览器的15个流程整理

    编译chromium 系统为windows, 国内在windows上编译chromium的资料比较少, 我这篇文章只能作为参考, 记录我遇到的一些问题,因为chromium团队也会修改了代码,或者编译 ...

  8. Google之Chromium浏览器源码学习——base公共通用库(二)

    上次提到Chromium浏览器中base公共通用库中的内存分配器allocator,其中用到了三方库tcmalloc.jemalloc:对于这两个内存分配器,个人建议,对于内存,最好是自己维护内存池: ...

  9. 浏览器-10 Chromium 移动版

    移动版 chromium 的iOS版和Android是为两个流行的移动操作系统设计的, UI方面进行了 较大的重新设计; 两者从外观上看颇为相似,但是其内部的渲染引擎的差别非常的大,原因在于iOS对应 ...

  10. 浏览器-09 javascript引擎和Chromium网络栈

    语言的运行 C/C++语言 使用编译器直接将它们编译成本地代码(机器指令),这是由开发人员在代码编写完成之后实施; 用户只是使用这些编译好的本地代码,这些本地代码被系统的加载器加载执行,由操作系统调度 ...

随机推荐

  1. ubuntu下常用命令

    目录 一.查找命令 二.打开相应文件 三.查看系统资源占用 四.Ubantu解压文件 五.虚拟机ubuntu server 14.0 根目录扩容 七.ubuntu 关机,重启,注销命令 1 关机命令 ...

  2. 廖雪峰网站:学习python基础知识—循环(四)

    一.循环 1.for names = ['Michal', 'Bob', 'tracy'] for name in names: print(name) sum = 0 for x in [1, 2, ...

  3. http.cof

    ## This is the main Apache HTTP server configuration file. It contains the# configuration directives ...

  4. Highcharts 环境配置

    Highcharts 环境配置 本章节我们将为大家介绍如何在网页中使用 Highcharts. Highcharts 依赖于 jQuery,所以在加载 Highcharts 前必须先加载 jQuery ...

  5. 完全揭秘log file sync等待事件-转自itpub

    原贴地址:http://www.itpub.net/thread-1777234-1-1.html   谢谢 guoyJoe 老大 这里先引用一下tanel poder大师的图: 什么是log fil ...

  6. Leetcode 1022. 可被 K 整除的最小整数

    1022. 可被 K 整除的最小整数  显示英文描述 我的提交返回竞赛   用户通过次数74 用户尝试次数262 通过次数75 提交次数1115 题目难度Medium 给定正整数 K,你需要找出可以被 ...

  7. 一、集合框架(Collection和Collections的区别)

    一.Collection和Map 是一个接口 Collection是Set,List,Queue,Deque的接口 Set:无序集合,List:链表,Queue:先进先出队列,Deque:双向链表 C ...

  8. sublime ctags跳转函数使用

    sublime 点击某函数 按F12可以查到相关函数文件 正题: 1.下载ctags客户端文件 http://prdownloads.sourceforge.net/ctags/ctags58.zip ...

  9. Linux查看操作系统版本命令

    有时候比如在决定下载软件版本的时候,我们需要确定当前系统的位数和发行版版本. 命令 作用 适用说明 uname -a 显示Linux内核版本和位数 通用,推荐 cat /proc/version 显示 ...

  10. 牛客网 PAT 算法历年真题 1002 :数字分类 (20)

    1002 :数字分类 (20) 时间限制 1000 ms 内存限制 32768 KB 代码长度限制 100 KB 判断程序 Standard (来自 小小) 题目描述 给定一系列正整数,请按要求对数字 ...