败犬日报 2025-04-29
1. 同一个 shared_ptr 的复制移动 reset 等操作不是线程安全的
(这个话题仔细一想其实很显然)
shared_ptr 使用了原子变量,可能会被误以为同一个 shared_ptr 复制移动是线程安全,实则不然。
例如,A 线程 reset 把引用计数减到 0,然后析构;B 线程恰好在析构前拷贝,就会获得已析构的非法对象,代码如下:
cpp
shared_ptr<int> a;
// 线程 A
a.reset(new int);
// 线程 B
auto b = a;
shared_ptr 的原子变量目的是保证不同 shared_ptr 的并发安全,重点是“不同”。
同一个 shared_ptr 复制、移动、reset 等操作想要线程安全,只靠引用计数的几个原子变量是不行的,需要额外结构。这也是 atomic<shared_ptr>
做的事情。
2. 经典劣质八股之 TCP “粘包”问题
TCP 是面向流的协议,没有“包”的概念。所谓的“包”是应用层划分的,那就应该应用层负责处理,完全不关 TCP 的事。
所以不构成问题。
可惜的是直到今天还有面试官会这个问题。
3. debug 没问题 release 会段错误
很可能是未定义行为。
可以编译一个 RelWithDebInfo 版本看看。
4. 多生产者多消费者,竞争激烈怎么办
要尽量规避竞争,一种容易实现的方式是分 shard + 异步(每个线程一个队列,任务通过哈希来分发)。
除此之外就是一个好的 MPMC queue 了,可以看下 folly 或 rigtorp 的实现。把 rigtorp 的 MPMC Queue 复制粘贴一下,改成 flexible array,丢到 shm 上即可。
(免责:这部分我不懂)