这篇研究两个问题: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. python记录_day30 多进程

    1.什么是进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 同一个程序执行两次,就会产生两个进程 ## 进程调度算 ...

  2. c# 操作文本文件

    计算机在最初只支持ASCII编码,但是后来为了支持其他语言中的字符(比如汉字)以及一些特殊字符(比如€),就引入了Unicode字符集.基于Unicode字符集的编码方式有很多,比如UTF-7.UTF ...

  3. ​ 用一个开发案例详解Oracle临时表

    ​ 用一个开发案例详解Oracle临时表 2016-11-14 bisal ITPUB  一.开发需求  最近有一个开发需求,大致需要先使用主表,或主表和几张子表关联查询出ID(主键)及一些主表字段 ...

  4. OpenStack设计与实现5——RESTful API和WSGI

    转https://segmentfault.com/a/1190000004361778 Tips:文章为拜读@xingjiarong 后有感而做的分享,先对作者表示感谢,附原文地址:http://b ...

  5. python中的IO模块

    1.简介 读写文件是常见的IO操作,python内置了读写文本的函数. 读写文件的模式描述如下: 模式 描述 r 以只读方式打开文件.文件的指针将会放在文件的开头.这是默认模式. rb 以二进制格式打 ...

  6. js中用来操作字符串的相关的方法

    var str = "zhufengpeixun2015yangfanqihang"; 字符串也是存在索引和length的 str.length 获取字符串的长度(字符的个数) 第 ...

  7. ActiveMQ broker解析

    在 ActiveMQ 中,broker 集中管理持久的.临时的 queue 和 topic. public class BrokerFilter implements Broker { // 省略其他 ...

  8. CentOS查看安装包会释放哪些文件

    1.查看软件包全称(以mysql为例) rpm -qa | grep -i mysql 2.查看释放出的文件(以MySQL-server-5.5.55-1.el6.x86_64为例) rpm -ql ...

  9. Linux第六周作业

    一 实验过程 1 先进入LinuxKernel环境下,更新menu代码到最新版,用到的命令为rm menu -rf //强制删除当前menu,git clone http://git.shiyanlo ...

  10. 跨域 jsonp 和 CORS 资料

    http://mp.weixin.qq.com/s/iAShnqvsOyV-Xd0Ft7Nl2Q HTML5安全:CORS(跨域资源共享)简介...ie67不要想了... http://www.cnb ...