Jason Pan

Google C++ 开源项目的格式

潘忠显 / 2020-06-29


从三个项目看Google C++的文件组织形式

一个功能涉及的文件

简单来说,一个功能涉及到的文件可能包括以下几种

Envoy

Timer相关

source/common/http/http1/conn_pool.h中有用到定时器。

#include "envoy/event/timer.h"
struct ActiveClient : ...{
    ...
    Event::TimerPtr connect_timer_;
    ...

    ActiveClient::ActiveClient(ConnPoolImpl& parent)
    : parent_(parent),
      connect_timer_(parent_.dispatcher_.createTimer([this]() -> void { onConnectTimeout(); })),...{
          ...
      }
}

在ActiveClient构造的时候,创建定时器并存使用unique_ptr的指针管理。

Timer的声明

Timer是个抽象的定时器事件类(abstract timer event),定义了几个接口:

自己实现的定时器类继承自Timer即可,比如timer_impl.h中的TimerUtils类。

Utils可以看做是`Utility helper functions的缩写,这种类我们大多称为“实用工具类”。

TimerUtils 实现了Timer的所有虚函数。对应两个文件

Q: 为什么timer_impl.h是放在source目录下而不是include目录下?

A: 是为了内部使用,而不是作为提供给外边库使用的。

parent_.dispatcher_.createTimer如何创建定时器

跟Timer类似,Envoy::Event::Dispatcher也是一个抽象类,这里调用的是Envoy::Http:Http1::ConnPoolImpl的成员变量dispatcher_的成员变量,而这个成员是在构造ConnPoolmpl的时候复制构造的。

ConnPoolImpl::ConnPoolImpl(Event::Dispatcher& dispatcher, Upstream::HostConstSharedPtr host,
                           Upstream::ResourcePriority priority,
                           const Network::ConnectionSocket::OptionsSharedPtr& options)
    : ConnPoolImplBase(std::move(host), std::move(priority)), dispatcher_(dispatcher),
      socket_options_(options),
      upstream_ready_timer_(dispatcher_.createTimer([this]() { onUpstreamReady(); })) {}

还有生产环境的实现:

/**
 * Production implementation of the ConnPoolImpl.
 */
class ProdConnPoolImpl : public ConnPoolImpl {
    ...

我们的主要目的是为了找个创建定时器的实现,追复杂调用关系就偏离主题了。可以直接看看dispatcher_impl.h中的DispatcherImpl中的createTimer即可。

TimerPtr DispatcherImpl::createTimer(TimerCb cb) { return createTimerInternal(cb); }

TimerPtr DispatcherImpl::createTimerInternal(TimerCb cb) {
  ASSERT(isThreadSafe());
  return scheduler_->createTimer(cb);
}

实际是使用LibeventScheduler创建的TimerImpl的对象,构造接受两个参数Libevent::BasePtrTimerCb cb

用到了libevent库。

#include "event2/event.h"

evtimer_assign(
      &raw_event_, libevent.get(),
      [](evutil_socket_t, short, void* arg) -> void { static_cast<TimerImpl*>(arg)->cb_(); }, this);

libevent库

https://libevent.org/

http://www.wangafu.net/~nickm/libevent-book/

internal 与 implementation

为什么会有Impl的存在?

https://en.cppreference.com/w/cpp/language/pimpl

createTimercreateTimerInternal

C++ Core Guidelines https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md

Anything not specifically forbidden is allowed.

C++中的虚函数是如何工作的

https://www.geeksforgeeks.org/virtual-function-cpp/

override 描述符的作用

编译时错误

三种方式的比较

头文件: envoy/event/timer.h

Envoy::Event::Timer