字节跳动面试准备
IPC: 进程间通信方式
-
管道(pipe): |, linux命令 grep wc -l sort
-
socket 通信 端口号
-
共享内存 (); 多个进程 fork
int shmget(key_t key, size_t size, int flag);
可以与信号量配合使用
- 信号 , sigint ctrl-c
线程和进程
理论上说是以线程的调度作为时间片(4ms)的单位
线程:最小的调度单位(有)
题主说的情况基本不会遇到。现代操作系统虽然都是 preemptive multitask。但是 99.99% 的情况下是一个进程 voluntarily relinquish CPU。比如说,一个进程读 disk 的时候,控制权就交给 disk controller 了,这时进程就被挂起了,直到 disk controller 告诉操作系统任务完成,这个进程才会再参与到 schedule 中。在 95% 以上的时间里,系统里的所有进程都是被挂起的:都在等待某个外围设备。现代操作系统中很少有进程发起全力计算两分钟以上的,对于 MBP 来说,这个时候风扇就已经开始高速了。CPU 的使用率:CPU 是不存在「什么都不做」的状态的。当所有进程都挂起的时候,操作系统会运行内核里的一个零号进程。这个进程占用 CPU 的百分比就是系统的 idle 率。在古老的 386 里,这个零号进程就是空循环。后来有了高级电源管理,这个零号进程就是调用高级电源管理的功能让 CPU 降频等等,把发热降下来。
gmapping
RBPF 粒子滤波 定位和已知定位的建图
- 去畸变
- 运动模型+gauss 粒子姿态 (里程计)
- scan_match 匹配: 计算e, 计算权重和累计权重 (爬山寻找最优位姿)
- 选择性重采样
- 更新栅格,计算地图
地图:
找权重伟大的粒子 的位姿和地图
最速下降法:直观上将本算法十分简单,直接按照梯度的反方向下降即可;缺点是过于贪心,容易呈锯齿状下降,从而增加迭代次数。
牛顿法:相对而言也非常直观,同时由于引入了二阶导数,可以处理一阶导为0的情况;但缺点是二阶导数具有非常大的计算量。
高斯牛顿法:在牛顿法的基础上进行了一定程度的简化,使用 [公式] 代替海塞矩阵,避免了二阶导数的计算;缺点在于 [公式] 很容易病态,导致无法得到正确的结果。
LM法:通过引入阻尼项使得 [公式] 不那么容易病态,并且可以通过调整阻尼完成在梯度法和牛顿法之间切换;缺点不太清楚。
HOA重建声场去确定声场方位,选择能量最大的方向最为最优可能的声源方向
但当部分麦克风损坏的情况,由于麦克风损坏,接受到能量最大方向的可能不是声源方向。机器人通过自主的旋转将好的麦克风对准声源方向。
具体做法是通过kalman filter 结合历史信息和每次观测的声源方向实现稳定的转向。
在定向确定后,结合里程计的信息就能进行定位。一般的只需要运动两次定位就可,但收集的数据越多实际上确定的位置越精准。但实际上每一次测量都可能存在误差, 包括里程计的误差和定向的误差,我们设计了评估不确定性的方法,并将它加入的优化的目标当中。
构造函数为什么不能是虚函数
构造函数是为了在编译阶段确定对象的类型以及为对象分配空间。
如果类中有虚函数,那就会在构造函数中初始化虚函数表,虚函数的执行需要依赖虚函数表。
如果构造函数是虚函数,那它就需要依赖虚函数表才执行,矛盾
所以构造函数不能是虚函数。
基类析构函数要是虚函数
如果不设置成虚函数,析构过程中只会用到基类的析构函数而不会用到子类的析构函数
虚函数表中有两个析构函数
一个标志为deleting,一个标志为complete
因为对象可以在栈构造也可以在堆构造;其中堆构造的析构需要执行delete,而栈内存的析构不需要执行delete,会被自动回收
虚继承
非虚继承时,D会继承两次A, 内部就会存储两份A的数据浪费空间,而且还有二义性。D调用A的方法时,由于有两个A,编译器也不知道调用哪一个A的方法,就会报错。所以有了虚继承,解决的空间浪费和二义性问题
在虚拟继承下,只有一个共享的基类子对象被继承,而无论该基类在派生层次中出现多少次。
共享的基类子对象被称为虚基类。
在虚继承下,基类子对象的复制及由此引起的二义性都被消除了
A *a = new Derive(); // A 为 Derive基类
RTTI 指针: 指向存储运行时类型信息(TYPE_INFO)的地址,用于运行时类型识别,用于typeid和dynamic_cast