chromium代码学习

2017-08-04  本文已影响0人  黄瓜苗苗的兜大宝

chromium代码学习

chromium开源工程中有太多值得学习的地方,值得我们通过一个单独的专题来记录对这个“伟大”工程的学习

base库Event事件实现方式

对于可等待的通知事件来说,“等待”部分实现的核心就是用锁来进行实现。在POSIX标准下,通过pthread_mutex_t来实现锁的功能。“通知”部分实现的核心则是通过条件变量来实现。在POSIX标准下,通过pthread_cond_t来实现通知的功能,pthread_cond_t需要一个pthread_mutex_t的配合来完成通知的功能。

主要的流程是

pthread_cond_init(&cond) //初始化pthread_cond_t变量
pthread_mutex_lock(&mutex) //锁住pthread_mutex_t变量
pthread_cond_wait(&cond, &mutex) //首先解锁mutex,然后等待cond被signal激活(线程X)
pthread_cond_signal(&cond) //将会signal激活等待在这个条件变量上的线程(并不是调度这个线程执行),并锁住mutex
pthread_mutex_unlock(&mutex) //解锁pthread_mutex_t变量

最后线程X,被OS调度后会执行wait后续的代码。POSIX为什么会前后两次lock、unlock呢?因为可等待的通知事件是可以被用在多个线程中,这些线程可以同时等待某个事件的完成。那么wait函数就需要是线程安全的,但wait函数要把等待线程的信息和事件关联起来,以及事件signal以后把线程信息和事件解除关联。所以就需要lock、unlock两次。

基于base库的APP全流程 基础消息循环

程序的入口:src/ios/wework/main.mm

作为普通的C语言入口函数main,其中实现的最重要的当然是消息循环。消息循环这块后面会专门的开专题来进行讲述。
除此之外,这个入口文件(函数)还负责:

运行时的环境:src/common/wework_runtime.h src/common/wework_runtime.cpp

作为APP运行时的载体,这个接口非常的简单就一个静态的创建方法+三个初始化、处理运行时消息和关闭消息循环的纯虚函数组成。

接下来我们进入到整个框架最关键、最灵魂也最复杂的,处理整个APP进程消息的WeWorkMainLoop。

消息循环:src/common/wework_main_loop.h src/common/wework_main_loop.cpp

这个类以及下一节要介绍的这一组类说夸张一点,是任何平台的客户端类程序的心脏,它为进程提供了可用的线程,驱动程序相应各类外部消息,管理进程类各个对象的生命周期。当客户端程序员已经熟练掌握了UI、逻辑、网络、数据、兼容层以及等等客户端的实现以后。就像医学院里,成绩最好的、最有理想的学生会选择外科,这部分佼佼者中的金字塔尖的学生会选择胸外科对心脏动手术一样。对消息循环的掌握对客户端程序员尤其重要。
这个类极其复杂,这里会抽丝剥茧,只讲其最精华的部分。

底层的消息循环:src/third_party/base/message_loop/ (主目录) message_loop.h message_loop.cc message_pump.h message_pump_mac.h.mm message_pump_libevent.h.cc message_pump_default.h.cc

这一部分是更底层的消息循环。从上面提供的涉及到的文件名称我们可以看到,pump就是那个驱动程序生生不息的心脏。接下来我们回答上一节留下的问题。要回答这个问题我们就要去base::MessageLoop的构造函数去看看它做了什么工作。不过在看之前,我们还是先简单分析一些这个类的构成

线程和Task:src/third_party/base/threading/thread.h src/common/wework_client_thread.h src/common/wework_client_thread_impl.h src/common/wework_client_thread_impl.cc

我们先来看线程方面的接口,一共两个 WeWorkThread 和Thread。前者提供了一组跨线程分发任务的接口,后者则提供了对线程本身的一个封装。

任务队列:src/third_party/base/message_loop/incoming_task_queue.h.cc

这个类用户维护输入(PostTaskXXX)的Task,因为Task多来自于其他线程,在Task进入队列的时候需要加锁。但整个APP进程内部的跨线程执行,仅仅只在Task进入队列的时候加锁,不需要程序员加锁。程序员只需要关注代码的逻辑,已经逻辑需要在合适的地方执行即可。这种跨线程只在进入队列的时候加锁一次的实现方法非常巧妙值得推荐,网上有很多很详细的文章深入的介绍这里的具体实现,建议大家找来看看。

可等待事件 : src/third_party/base/synchronization/waitable_event.h.cc

对于可等待的通知事件来说,“等待”部分实现的核心就是用锁来进行实现。在POSIX标准下,通过pthread_mutex_t来实现锁的功能。“通知”部分实现的核心则是通过条件变量来实现。在POSIX标准下,通过pthread_cond_t来实现通知的功能,pthread_cond_t需要一个pthread_mutex_t的配合来完成通知的功能。

主要的流程是

pthread_cond_init(&cond) //初始化pthread_cond_t变量
pthread_mutex_lock(&mutex) //锁住pthread_mutex_t变量
WaitableEvent //调用SyncWaiter记录下当前线程(等待线程)的相关信息
pthread_cond_wait(&cond, &mutex) //首先解锁mutex,然后等待cond被signal激活(线程X)
pthread_cond_signal(&cond) //将会signal激活等待在这个条件变量上的线程(并不是调度这个线程执行),并锁住mutex
pthread_mutex_unlock(&mutex) //解锁pthread_mutex_t变量

最后线程X,被OS调度后会执行wait后续的代码。POSIX为什么会前后两次lock、unlock呢?因为可等待的通知事件是可以被用在多个线程中,这些线程可以同时等待某个事件的完成。那么wait函数就需要是线程安全的,但wait函数要把等待线程的信息和事件关联起来,以及事件signal以后把线程信息和事件解除关联。所以就需要lock、unlock两次。

上一篇 下一篇

猜你喜欢

热点阅读