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,暂时分析到这里,觉得好乱呐,不过貌似还木有谁这么分析过,大家多拍砖。嘎嘎


    原文作者:xiaolomg
    原文地址: https://blog.csdn.net/boyxiaolong/article/details/17034029
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞