陪你度过漫长岁月

源码阅读《CarlaUE5整体架构》

前言

总结了一下CarlaUE5的整体代码架构,该总结基于以下代码:

整体架构


整体架构

Server架构


Server架构

Client架构


Client架构

PythonAPI


PythonAPI架构

一些C++知识点

weak_ptr

  • motivation:只有shared_ptr的话会出现循环引用的问题
  • 具体来说,就是搞一个阉割版的,不会影响计数的“智能指针”,也就是weak_ptr
  • weak_ptr不能直接用,只能先通过.lock()提级(构造)为shared_ptr之后再用
  • 这个blog这个blog讲解得挺好的

atomic

  • motivation:针对变量的高效线程安全读写工具
  • 相比lock, mutex这些要跟跟内核打交道(有用户态和内核态的切换开销)的多线程工具,atomic属于硬件指令集的工具,效率更高
  • 对于atomic<int> ai;,需要调用ai.load()ai.store(1)进行读写
  • 又由于编译器会对代码的实际执行顺序进行优化,atomic提供了一些指令去控制代码的执行顺序,具体可以参考这个blog

enable_shared_from_this

  • motivation:使得成员函数使用shared_ptr<T>(this)成为可能。假如没有额外支持的话,成员函数直接裸使用shared_ptr<T>(this)会导致this被析构两次
  • 核心要做的事情就是使得对象知道管理自己的shared_ptr是什么。具体来说:
    • esft是个模板类,我们需要继承他。这个类里有一个weak_ptr成员,语意是指向管理本对象的shared_ptr;同时会提供一个shared_from_this方法,去调用weak_ptr.lock()
    • 在调用make_shared的时候,会调用dynamic_cast来检查当前要构造的对象是否继承自esft,假如是,就会将其weak_ptr对象指向shared_ptr
  • 关于这部分,可以参考这个blog

mutable

  • motivation:允许const成员函数修改的成员变量

pImpl

  • motivation
    • 完全隐藏实现细节
    • 避免修改成员变量引起头文件变化
  • 具体来说,就是
    • 在类的private里面前向声明一个Impl
    • 成员变量只保留一个指向Impl类的unique_ptr

compare_exchange

  • motivation:解决多线程编程时,读到的值在要用的时候可能已经被修改的问题,主要用于条件赋值,否则直接用store就好了
  • 思路就是在用的时候再验一下货。具体来说,就是搞了一个包含比较和赋值这两个指令的原子操作,只有当selfexpected相等的时候,self才会被赋值为target
  • 这个也被叫做CAS(Compare and Swap),属于无锁编程的概念。
  • 可以参考这个blog