提问记录
24-06-27
DDS可靠性相关 -> 如何保证可靠性?接收端来不及处理时,如何保证?
- DDS可以理解为是一种传输协议,它的可靠性可以保证:发端发送一条消息后,可以到达接收端的DDS协议栈中,并驻留在接收端的History中。如果接收端的应用层来不及处理新收到的消息,那就不立即处理,后续可以使用read接口从协议栈中获取之前接收到的数据。
- 上述可能会出现接收端缓存满,而尚有消息未处理的情况:此时,就需要扩大History的消息缓存数目。这里就是History QoS 与 Resource QoS这两种不同服务质量要求之间的trade了。
MCU上做开发与Linux用户态开发有什么不同?分别有哪些需要注意的内容?
- MCU上直接看到真实物理内存,Linux用户态多了一层虚拟地址转换。因此在MCU上做开发时,更要注意对指针的使用。
- MCU上有时Linker,链接脚本,程序、变量存放位置;Linux用户态不用考虑这些问题。
- 调试时,MCU上遇到TRAP等问题,要去翻具体的芯片架构手册进行排查;Linux用户态有一套标准的exception机制。
- MCU上做开发更类似于Linux内核态驱动开发。
- MCU上有时需要考虑boot的问题,Linux用户态不用考虑。
- MCU上开发一般只会用到静态库,而Linux上还会有动态库。
(之前软硬件结合提到了对指针的“恍然大悟”)那你现在是如何理解指针的?
- 指针就是一个普通的变量,对它进行加减乘除,函数参数,就像普通变量那样使用
- 重点在于如何使用指针变量,如何解释指针 -> 这里就得说一下指针类型转换
- 使用时,相比于普通变量,要多考虑一层:它指向了某块内存区域!内存区域的大小与指针指向的对象类型有关
- 指针使用:大部分都会取成员 -> 指针指向的对象类型是什么?这个问题也要时刻注意
- 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语言中,常把指针和数组进行比较。
用一个词形容操作系统
- 管理者
- 根据管理的内容不同,OS又可以分为宏内核/微内核
- MCU上的OS一般只有CPU管理的功能
- SoC上使用基于Linux的操作系统,还会有内存管理,进程通信,文件系统等功能
24-07-04
如何在不使用额外变量的情况下,交换两个整形变量的值
方法一:采用数学运算
1
2
3x = x + y; // -> 虽然这里可能会有溢出的情况,但**由于**负数采用补码的方式表示,后续运算后,也能实现交换的目的
y = x - y;
x = x - y;方法二: 采用异或运算
1
2
3x = x ^ y;
y = x ^ y;
x = x ^ y;
叠砖块问题
- 要保证第二块及以上所有砖的“重心和”落在第一块砖内
这题要分情况讨论: - 如果每块砖伸出的长度可以自由调整, 参考,可以证明:以1/2n的规律无限延伸
- 如果每块砖伸出的长度为固定大小,可以证明:最远可伸出1/2n
- 要保证第二块及以上所有砖的“重心和”落在第一块砖内
“叠砖块问题”的启发
- 面试时要大胆的说出自己的直觉,并且额外补充说明:需要进一步的分析与证明
有符号数溢出问题
- 要注意负数以补码的形式存储:绝对值的反码+1
- unsigned char 和 signed char表示的数据范围是不一样的
位数扩展
- 有符号数:转为更大数据类型采用的是符号扩展 -> 添加最高有效位的值【正为0, 负为1】
- 无符号数:转换为更大数据类型采用的是零扩展 -> 添加0
CPU位数/字长
- 机器字长、存储字长、指令字长
- CPU位数 = CPU中寄存器位数 = CPU一次能够并行处理的数据宽度
- ~= 数据总线宽度【一般来说】
- 机器字长 ~= 数据总线宽度
24-07-27
- 当一个问题卡了一段时间,切没有任何头绪的时候,说明需要补相关的知识了
- 站在更高层级【本质层级】去看一个问题,就会很通透
24-08-01
如何理解声明与定义
- 对于变量的声明与定义
声明:不会为变量分配地址和内存空间,仅说明变量的性质
变量的声明必须得加上extern
函数的声明可加可不加
定义:会为变量分配地址和内存空间
- 函数定义时一定有函数体
- 对于结构体类型的声明和定义
一般前置声明用的比较多,用于解决结构体嵌套定义问题
定义就比较容易理解了
扩展
- C语言中变量有存储类型和数据类型两种类型
存储类型-相关的关键字
自动变量(auto)—> 很少使用
静态变量 (static)–> 具有隐藏符号的作用
外部变量 (extern)
相对于 static来识记就比较简单了
在函数外部定义的变量,如果没有为其指定存储类型,那么它默认为extern类型
int a; int a; 是可以的
寄存器变量 (register) -> 很少使用
C vs CPP
遇到最困难的事情
从0到1是最困难的
自己也乐于从0到1的过程
看RTOS的代码:-> 自己也希望今后有机会针对一款全新的芯片,完成Linux/甚至自研操作系统的bring up
任务切换
初始任务上下文的构建【栈指针、函数入口】
过程中涉及到架构相关的寄存器操作:
特权级
arm64的四种特权级切换
glibc -> linux ABI规范的遵守
- 系统调用约定
24-08-10
- 自我思考
CAN -> FlexRay -> Ethernet
- 速率提升
- 实时性方面
24-08-12
- Linux的几种调度策略
- 实时调度策略是怎么实现的
- 详见[[Linux - 调度策略]]
- 智能指针使用时的注意事项
- 循环引用
- 管理的对象内部含有智能指针,且形成循环引用
make_sharedvsstd::shared_ptr(object)- 多线程修改引用计数:原子操作,线程安全
- 裸指针和智能指针混用
- 将裸指针赋给智能指针,却又在退出作用域时,主动delete裸指针 => 造成double delete
- 智能指针混用:出作用域时,都释放,导致double
1
2
3
4
5void fun()
{
std::unique_ptr<Type> t(new Type);
std::shared_ptr<Type> t1(t.get());
} - 不要管理同一个裸指针
1
2
3
4
5
6void 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
8void fun()
{
auto ptr = std::make_shared<Type>();
auto a= ptr.get();
std::shared_ptr<Type> t(a);
// 很容易就手滑了
delete a;
} - 只管理堆上的对象
1
2
3
4
5void fun()
{
Type t;
std::shared_ptr<Type> ptr(&t);
}
- 循环引用
- Linux 伙伴系统与slab内存分配器 -> 确实还没有成体系的看内存子系统,该开始着手看了
- 伙伴系统对物理内存的管理是以page为单位的,粒度比较大
- ==slab==是将页拆分成小内存块进行管理,一般和伙伴系统配合使用,它是对伙伴系统的改进和补充
- slab首先通过伙伴系统的接口向伙伴系统申请一个或多个物理页,然后将其切割成固定大小的块,缓存起来,当分配此大小的内存块的时候,直接返回缓存的内存块,用户释放时,会释放给slab继续缓存起来。slab中的内存块使用链表链起来
- 有三种类似的内存分配器
- slab:是内核中最早出现的分配器,随着内核的发展,其实现越来越臃肿
- slub:面向小型嵌入式系统很少内存的简单管理,比如32MB
- slob:是一个轻量级的slab,一般使用在嵌入式系统中
24-09-20
动态库、静态库的区别
链接程序加载过程:
动态链接程序在哪?
24-09-29
- Linux RCU
- 为什么Fast-DDS没有采用整体式序列化
- reliable/best-effort想要使用同一套Group+Sender的RTPS数据发送模式
- reliable模式下,对于不同的远端reader,其包含的submessage是不同的;但是RTPS Header是相同的;
- sub message添加到Group的sub_msg中,之后将其append到RTPS M message的尾部 ->
insert_submessage() - 针对不同的远端reader,想要使用同一个RTPS Message发送,因此只能拷贝
- 一个data sub_message含有前置的dst/ts 子消息
- sub message添加到Group的sub_msg中,之后将其append到RTPS M message的尾部 ->
insert_submessage()- add_data()
- add_heartbeat()
- add_gap()
- add_acknack()
- add_nackfrag()
24-10-15
数组中有一个元素的数目超过了一半,找出这个数。尽量低的时间、空间复杂度
- 169. 多数元素
提问记录
http://example.com/2024/06/28/提问记录/