google protobuf源码分析1

突然来了兴趣,相分析它的源码,找最简单的开始读:

里面有actomicops.h里面写了几个线程安全的交换函数,发现只在一个地方用了:

void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure) {
  internal::AtomicWord state = internal::Acquire_Load(once);
  // Fast path. The provided closure was already executed.
  if (state == ONCE_STATE_DONE) {
    return;
  }
  // The closure execution did not complete yet. The once object can be in one
  // of the two following states:
  //   - UNINITIALIZED: We are the first thread calling this function.
  //   - EXECUTING_CLOSURE: Another thread is already executing the closure.
  //
  // First, try to change the state from UNINITIALIZED to EXECUTING_CLOSURE
  // atomically.
  state = internal::Acquire_CompareAndSwap(
      once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_CLOSURE);
  if (state == ONCE_STATE_UNINITIALIZED) {
    // We are the first thread to call this function, so we have to call the
    // closure.
    closure->Run();
    internal::Release_Store(once, ONCE_STATE_DONE);
  } else {
    // Another thread has already started executing the closure. We need to
    // wait until it completes the initialization.
    while (state == ONCE_STATE_EXECUTING_CLOSURE) {
      // Note that futex() could be used here on Linux as an improvement.
      SchedYield();
      state = internal::Acquire_Load(once);
    }
  }
}

其中typedef internal::AtomicWord ProtobufOnceType;

闭包:

class LIBPROTOBUF_EXPORT Closure {
 public:
  Closure() {}
  virtual ~Closure();


  virtual void Run() = 0;


 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
};


函数里面会有原子调用,比如这个:

PVOID __cdecl InterlockedCompareExchangePointer(
  _Inout_  PVOID volatile *Destination,
  _In_     PVOID Exchange,
  _In_     PVOID Comparand
);
The function compares the  Destination  value with the  Comparand  value. If the  Destination  value is equal to the Comparand  value, the  Exchange  value is stored in the address specified by  Destination . Otherwise, no operation is performed.

就是比较第一个和第三个参数,比如相等,就把第二个参数赋给第一个参数,并返回这个值。


这里就是检查状态,

1.如果state是ONCE_STATE_DONE就返回;

2.state是ONCE_STATE_EXECUTING_CLOSURE,就把state转为ONCE_STATE_UNINITIALIZED

3.如果是ONCE_STATE_UNINITIALIZED,就执行闭包操作;否则就是在其他线程执行闭包,这时候就要忙检测state,一直到闭包执行结束。


不过悲剧的是,现在版本没有闭包操作的支持,如果protobuf再更新,应该可以,C++11已经支持了嘛。

不过为毛是在其他线程执行?还不清楚。


接着是上一层的调用:


inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
  if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
    internal::FunctionClosure0 func(init_func, false);
    GoogleOnceInitImpl(once, &func);
  }
}

template <typename Arg>
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg*),
    Arg* arg) {
  if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
    internal::FunctionClosure1<Arg*> func(init_func, false, arg);
    GoogleOnceInitImpl(once, &func);
  }
}

哇哦,里面有函数闭包:

class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure {
 public:
  typedef void (*FunctionType)();

  FunctionClosure0(FunctionType function, bool self_deleting)
    : function_(function), self_deleting_(self_deleting) {}
  ~FunctionClosure0();

  void Run() {
    bool needs_delete = self_deleting_;  // read in case callback deletes
    function_();
    if (needs_delete) delete this;
  }

 private:
  FunctionType function_;
  bool self_deleting_;
}

FunctionClosure0就是一个可以自我销毁的闭包,里面会执行完传过来的函数指针,然后干掉自己。

这下清楚了,是GoogleOnceInit这个函数里面穿了一个函数指针,一个状态。会检测状态,来决定是否执行这个函数。


然后有一个类在构造时就用了这些:

LogSilencer::LogSilencer() {
  internal::InitLogSilencerCountOnce();
  MutexLock lock(internal::log_silencer_count_mutex_);
  ++internal::log_silencer_count_;
};

void InitLogSilencerCountOnce() {
  GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
}

这里log_silencer_count_init_ = GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED

根据前面的分析,也就是说要执行闭包操作,实质是 &InitLogSilencerCount(函数指针)的执行

void InitLogSilencerCount() {
  log_silencer_count_mutex_ = new Mutex;
  OnShutdown(&DeleteLogSilencerCount);
}

这里new出来一个Mutex,就是把关键段封装了一下。

而这个OnShutdown(&DeleteLogSilencerCount);是搞神马的呢?

void OnShutdown(void (*func)()) {
  GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions);
  MutexLock lock(shutdown_functions_mutex);
  shutdown_functions->push_back(func);
}

我擦,还有一个GoogleOnceInit调用,嵌套啊。

void InitShutdownFunctions() {
  shutdown_functions = new vector<void (*)()>;
  shutdown_functions_mutex = new Mutex;
}

搞出来一个关闭函数指针容器,一个关闭函数互斥锁。

之后会上锁,把DeleteLogSilencerCount放进shutdown_functions里面。

肯定是最后关闭的时候要调用:

void ShutdownProtobufLibrary() {
  internal::InitShutdownFunctionsOnce();


  // We don't need to lock shutdown_functions_mutex because it's up to the
  // caller to make sure that no one is using the library before this is
  // called.


  // Make it safe to call this multiple times.
  if (internal::shutdown_functions == NULL) return;


  for (int i = 0; i < internal::shutdown_functions->size(); i++) {
    internal::shutdown_functions->at(i)();
  }
  delete internal::shutdown_functions;
  internal::shutdown_functions = NULL;
  delete internal::shutdown_functions_mutex;
  internal::shutdown_functions_mutex = NULL;
}

在这个函数里InitShutdownFunctionsOnce不会执行了,因为已经初始化完成会返回而不执行任何调用了。

执行关闭函数vec里面的所有函数,最后删掉vec,删除mutex。

ok,暂时分析到这里,觉得好乱呐,不过貌似还木有谁这么分析过,大家多拍砖。嘎嘎


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值