提问记录

24-06-27

  1. DDS可靠性相关 -> 如何保证可靠性?接收端来不及处理时,如何保证?

    • DDS可以理解为是一种传输协议,它的可靠性可以保证:发端发送一条消息后,可以到达接收端的DDS协议栈中,并驻留在接收端的History中。如果接收端的应用层来不及处理新收到的消息,那就不立即处理,后续可以使用read接口从协议栈中获取之前接收到的数据。
    • 上述可能会出现接收端缓存满,而尚有消息未处理的情况:此时,就需要扩大History的消息缓存数目。这里就是History QoS 与 Resource QoS这两种不同服务质量要求之间的trade了。
  2. MCU上做开发与Linux用户态开发有什么不同?分别有哪些需要注意的内容?

    • MCU上直接看到真实物理内存,Linux用户态多了一层虚拟地址转换。因此在MCU上做开发时,更要注意对指针的使用。
    • MCU上有时Linker,链接脚本,程序、变量存放位置;Linux用户态不用考虑这些问题。
    • 调试时,MCU上遇到TRAP等问题,要去翻具体的芯片架构手册进行排查;Linux用户态有一套标准的exception机制。
    • MCU上做开发更类似于Linux内核态驱动开发。
    • MCU上有时需要考虑boot的问题,Linux用户态不用考虑。
    • MCU上开发一般只会用到静态库,而Linux上还会有动态库。
  3. (之前软硬件结合提到了对指针的“恍然大悟”)那你现在是如何理解指针的?

    • 指针就是一个普通的变量,对它进行加减乘除,函数参数,就像普通变量那样使用
    • 重点在于如何使用指针变量,如何解释指针 -> 这里就得说一下指针类型转换
    • 使用时,相比于普通变量,要多考虑一层:它指向了某块内存区域!内存区域的大小与指针指向的对象类型有关
    • 指针使用:大部分都会取成员 -> 指针指向的对象类型是什么?这个问题也要时刻注意
    • c++中,class C 继承于 class B , class A。C v_c; B* p_b = &v_c; A* p_a = &v_c,这三行语句,p_b的值与p_a的值是不一样的!
    • 在c语言中,常把指针和数组进行比较。
  4. 用一个词形容操作系统

    • 管理者
    • 根据管理的内容不同,OS又可以分为宏内核/微内核
    • MCU上的OS一般只有CPU管理的功能
    • SoC上使用基于Linux的操作系统,还会有内存管理,进程通信,文件系统等功能

24-07-04

  1. 如何在不使用额外变量的情况下,交换两个整形变量的值

    • 方法一:采用数学运算

      1
      2
      3
      x = x + y;  // -> 虽然这里可能会有溢出的情况,但**由于**负数采用补码的方式表示,后续运算后,也能实现交换的目的
      y = x - y;
      x = x - y;
    • 方法二: 采用异或运算

      1
      2
      3
      x = x ^ y;
      y = x ^ y;
      x = x ^ y;
  2. 叠砖块问题

    • 要保证第二块及以上所有砖的“重心和”落在第一块砖内
      这题要分情况讨论:
    • 如果每块砖伸出的长度可以自由调整, 参考,可以证明:以1/2n的规律无限延伸
    • 如果每块砖伸出的长度为固定大小,可以证明:最远可伸出1/2n
  3. “叠砖块问题”的启发

    • 面试时要大胆的说出自己的直觉,并且额外补充说明:需要进一步的分析与证明
  4. 有符号数溢出问题

    • 要注意负数以补码的形式存储:绝对值的反码+1
    • unsigned char 和 signed char表示的数据范围是不一样的
  5. 位数扩展

    • 有符号数:转为更大数据类型采用的是符号扩展 -> 添加最高有效位的值【正为0, 负为1】
    • 无符号数:转换为更大数据类型采用的是零扩展 -> 添加0
  6. CPU位数/字长

24-07-27

  1. 当一个问题卡了一段时间,切没有任何头绪的时候,说明需要补相关的知识了
  2. 站在更高层级【本质层级】去看一个问题,就会很通透

24-08-01

  1. 如何理解声明与定义

    • 对于变量的声明与定义

    声明:不会为变量分配地址和内存空间,仅说明变量的性质

    • 变量的声明必须得加上extern

    • 函数的声明可加可不加

    定义:会为变量分配地址和内存空间

    • 函数定义时一定有函数体
    • 对于结构体类型的声明和定义

    一般前置声明用的比较多,用于解决结构体嵌套定义问题

    定义就比较容易理解了

  2. 扩展

    • C语言中变量有存储类型数据类型两种类型

    存储类型-相关的关键字

    • 自动变量(auto)—> 很少使用

    • 静态变量 (static)–> 具有隐藏符号的作用

    • 外部变量 (extern)

      • 相对于 static来识记就比较简单了

      • 在函数外部定义的变量,如果没有为其指定存储类型,那么它默认为extern类型

      • int a; int a; 是可以的

    • 寄存器变量 (register) -> 很少使用

  3. C vs CPP

  4. 遇到最困难的事情

    • 从0到1是最困难的

    • 自己也乐于从0到1的过程

    • 看RTOS的代码:-> 自己也希望今后有机会针对一款全新的芯片,完成Linux/甚至自研操作系统的bring up

      • 任务切换

      • 初始任务上下文的构建【栈指针、函数入口】

      • 过程中涉及到架构相关的寄存器操作:

        • 特权级

        • arm64的四种特权级切换

      • glibc -> linux ABI规范的遵守

        • 系统调用约定

24-08-10

  • 自我思考

CAN -> FlexRay -> Ethernet

  • 速率提升
  • 实时性方面

24-08-12

  1. Linux的几种调度策略
  2. 实时调度策略是怎么实现的
    • 详见[[Linux - 调度策略]]
  3. 智能指针使用时的注意事项
    • 循环引用
      • 管理的对象内部含有智能指针,且形成循环引用
    • make_shared vs std::shared_ptr(object)
    • 多线程修改引用计数:原子操作,线程安全
    • 裸指针和智能指针混用
      • 将裸指针赋给智能指针,却又在退出作用域时,主动delete裸指针 => 造成double delete
    • 智能指针混用:出作用域时,都释放,导致double
      1
      2
      3
      4
      5
      void fun()
      {
      std::unique_ptr<Type> t(new Type);
      std::shared_ptr<Type> t1(t.get());
      }
    • 不要管理同一个裸指针
      1
      2
      3
      4
      5
      6
        void fun() 
      {
      auto ptr = new Type;
      std::shared_ptr<Type> t(ptr);
      std::shared_ptr<Type> t1(ptr);
      }
    • 避免使用get获取裸指针
      1
      2
      3
      4
      5
      6
      7
      8
      void fun()
      {
      auto ptr = std::make_shared<Type>();
      auto a= ptr.get();
      std::shared_ptr<Type> t(a);
      // 很容易就手滑了
      delete a;
      }
    • 只管理堆上的对象
      1
      2
      3
      4
      5
      void fun()
      {
      Type t;
      std::shared_ptr<Type> ptr(&t);
      }
  4. Linux 伙伴系统与slab内存分配器 -> 确实还没有成体系的看内存子系统,该开始着手看了
    • 伙伴系统对物理内存的管理是以page为单位的,粒度比较大
    • ==slab==是将页拆分成小内存块进行管理,一般和伙伴系统配合使用,它是对伙伴系统的改进和补充
      • slab首先通过伙伴系统的接口向伙伴系统申请一个或多个物理页,然后将其切割成固定大小的块,缓存起来,当分配此大小的内存块的时候,直接返回缓存的内存块,用户释放时,会释放给slab继续缓存起来。slab中的内存块使用链表链起来
    • 有三种类似的内存分配器
      • slab:是内核中最早出现的分配器,随着内核的发展,其实现越来越臃肿
      • slub:面向小型嵌入式系统很少内存的简单管理,比如32MB
      • slob:是一个轻量级的slab,一般使用在嵌入式系统中

24-09-20

  1. 动态库、静态库的区别

  2. 链接程序加载过程:

  3. 动态链接程序在哪?

24-09-29

  1. Linux RCU
  2. 为什么Fast-DDS没有采用整体式序列化
    1. reliable/best-effort想要使用同一套Group+Sender的RTPS数据发送模式
    2. reliable模式下,对于不同的远端reader,其包含的submessage是不同的;但是RTPS Header是相同的;
      • sub message添加到Group的sub_msg中,之后将其append到RTPS M message的尾部 -> insert_submessage()
      • 针对不同的远端reader,想要使用同一个RTPS Message发送,因此只能拷贝
      • 一个data sub_message含有前置的dst/ts 子消息
    3. insert_submessage()
      • add_data()
      • add_heartbeat()
      • add_gap()
      • add_acknack()
      • add_nackfrag()

24-10-15

  1. 数组中有一个元素的数目超过了一半,找出这个数。尽量低的时间、空间复杂度
    - 169. 多数元素


提问记录
http://example.com/2024/06/28/提问记录/
作者
Cyokeo
发布于
2024年6月28日
许可协议