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

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

google protobuf源码分析1相关推荐

  1. 【Android Protobuf 序列化】Protobuf 使用 ( Protobuf 源码分析 | 创建 Protobuf 对象 )

    文章目录 一.Protobuf 源码分析 二.创建 Protobuf 对象 三.完整代码示例 四.参考资料 一.Protobuf 源码分析 Protobuf 源文件如下 : addressbook.p ...

  2. Google Mock(Gmock)简单使用和源码分析——源码分析

    源码分析 通过<Google Mock(Gmock)简单使用和源码分析--简单使用>中的例子,我们发现被mock的相关方法在mock类中已经被重新实现了,否则它们也不会按照我们的期待的行为 ...

  3. Okhttp源码分析以及Google Gson解析json数据实例

    Okhttp Github的Okhttp OkHttp是一个高效的HTTP客户端,它有以下默认特性: 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接 透明的GZIP压缩减少响 ...

  4. 【我的渲染技术进阶之旅】Google开源的基于物理的实时渲染引擎Filament源码分析:Android版本的Filament第一个示例:sample-hello-triangle

    文章目录 一.效果展示 二.之前的博客 三.示例工程sample-hello-triangle源码分析 3.1 项目源码路径 3.2 分析源码 3.2.1 分析AndroidManifest.xml ...

  5. caffe.proto源码分析

    一什么是protocol buffer 二caffeproto中的几个重要数据类型 三caffeproto源码 分析caffe源码,看首先看caffe.proto,是明智的选择.好吧,我不是创造者,只 ...

  6. hadoop-common2.7源码分析之ProtobufRpcEngine(RPC实现)

    概述 ProtobufRpcEngine是在RPC通信过程中,使用ptotobuf作为数据交换格式的RPC实现类. 对ProtobufRpcEngine的源码分析将围绕RPC概念模型展开. RPC概念 ...

  7. Brpc 服务端收包源码分析(一)

    文章目录 server端使用 brpc::Server::AddService初始化各种数据 StartInternal内部其余服务也调用该函数 接收连接套接字StartAccept请求 ResetF ...

  8. Dubbo源码分析:小白入门篇

    关注公众号"java后端技术全栈" 回复"000"获取优质面试资料 大家好,我是老田 答应了小伙伴的Dubbo源码分析系列,今天终于来了,希望不是很晚. 主要也 ...

  9. TeamTalk源码分析(十一) —— pc客户端源码分析

           --写在前面的话  在要不要写这篇文章的纠结中挣扎了好久,就我个人而已,我接触windows编程,已经六七个年头了,尤其是在我读研的三年内,基本心思都是花在学习和研究windows程序上 ...

最新文章

  1. List集合与Array数组之间的互相转换
  2. Flex AdvancedDataGrid 数据展示异常
  3. Xcode 9 快速跳转到定义新姿势(Jump to Definition)
  4. 【转】多语言的正则表达式,我们应该掌握
  5. 图解Linux系统启动流程
  6. 2015.7.17( NOI2015 day1 )
  7. 飞秋下载2010正式版_飞秋下载
  8. hive动态分区shell_Hive/Shell 创建Hive 库 ,表脚本,Hive 动态增加分区脚本
  9. qemu-kvm 代码分析
  10. DOM-window下的常用子对象-location-刷新页面
  11. Windows 命令 netstat 查看网络端口、telnet 检测对方端口是否可用
  12. c++ time_t和tm
  13. Ubuntu20.04安装网易云音乐播放器
  14. PS图片上传图片 同时生成微缩图
  15. 微信小程序uniapp高德开放平台路线规划1对多导航路线方法记录
  16. matlab 读取dbf文件
  17. 博途v15模拟量转换_TIA博途模拟量测量与工程量转换
  18. DynaTrace Ajax Edition:IE浏览器性能分析工具
  19. 中国计算机协会(CCF)A类期刊和会议
  20. Cadence Allegro元件封装制作流程

热门文章

  1. Access数据库偏移注入
  2. mysql 中文 3个字节_mysql里一个中文汉字占多少字节数?
  3. 计算机课遇到游戏,信息技术课玩游戏的现象及想法
  4. 区块链是什么?简单理解区块链
  5. 解决电脑开机黑屏只有鼠标的问题
  6. 180/360度舵机控制方法
  7. CABasicAnimation,CAKeyframeAnimation,CATransition,CAAnimationGroup,UIBezierPath之间做动画的不同点和各自的使用范围。
  8. Picosmos 一键智能抠图
  9. APP专项测试之耗电量测试
  10. python利用danmu实时获取斗鱼等直播网站字幕