面灵AI→

迈瑞医疗软件开发一面(时序数据与并发队列)

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

  1. 自我介绍。
  2. 项目二:介绍一下这个项目?是个人项目还是团队项目?团队大概多少个人?上面写的 xxx 是怎样的?时序数据有哪些?频率是多少、数据量多大?有做断线重连吗?设计过程中有没有遇到什么问题?怎么解决的?
  3. 实习:怎么找到这个实习?主要做的什么?为什么用 DDS?
  4. 其他:有了解我们公司吗?期望城市是哪?哪里人?
  5. 算法手撕:实现一个固定容量 N 的环形队列,支持多个生产者和消费者并发。
  6. 拉姆达表达式了解吗?智能指针了解吗?
  7. 反问。

《参考解析》

手撕:多生产者多消费者环形队列:要点是把「同步」和「环形索引」两件事分开做对。① 数据结构:T buffer[N]、head(读位置)、tail(写位置)、size(当前元素数),容量固定不分配。② 空/满判定:留一个空槽(满 = (tail + 1) % N == head)或用独立的 size/计数信号量,后者语义更清晰,也更适合「按元素个数阻塞」。③ 索引必须回绕:tail = (tail + 1) % N,注意用 % 或位运算(N 取 2 的幂时用 & (N-1) 更快,但要求 N 是 2 的幂,用之前要说明这个前提)。④ 同步:C++ 里最简洁的实现是 std::mutex + 两个 std::condition_variable(not_empty、not_full)——生产者拿锁、while (size == N) not_full.wait(lock)、写入、++size、not_empty.notify_one();消费者对称(while (size == 0) not_empty.wait(lock)、读取、--size、not_full.notify_one())。注意 wait 必须放在 while 循环里(防止虚假唤醒和惊群),锁只包住对共享状态的修改,不要把耗时逻辑放在临界区里。⑤ 进阶:如果要求极致性能,用无锁环形队列——head/tail 用 std::atomic<size_t>,生产者 CAS 抢占写槽位、消费者 CAS 抢读槽位,配合 memory_order_acquire/release;要处理 ABA 与「写槽位已占但数据未写完」的问题(可用序号回绕方案:tail 单调递增,槽位索引取 tail % N,通过序号差判断满空,天然避免 ABA)。⑥ 加分项:指出不同元素类型(T 是否可平凡拷贝)影响是 move 还是 memcpy、缓存行伪共享要给 head/tail 加 padding、以及压测时用多线程 + -fsanitize=thread 检查数据竞争。

DDS 为什么适合这类系统:DDS(Data Distribution Service)是发布/订阅式的实时数据中间件,标准由 OMG 维护,医疗设备、工业控制、机器人里用得多。选它的理由:① 数据为中心的发布订阅模型,节点间去中心化、点对点传输,没有单点中间件瓶颈,适合设备内部与设备之间高频小包的数据分发;② 内置丰富的 QoS 策略——可靠性(best-effort / reliable)、持久性(durability)、历史深度(history depth)、截止时间(deadline)、活跃性(liveliness)、资源限制,可按话题逐个配置,实时数据用 best-effort 追最新值、关键事件用 reliable 保证不丢;③ 自动发现(无需手写服务注册与心跳,节点上下线自动感知)和强类型 IDL 定义,多语言(C++/C/Java/Python)互通;④ 支持多播,一对多分发效率高。对照方案是 MQTT(更适合跨网络、云边、弱网,但要经过 broker)、ZeroMQ(更轻但 QoS 与发现要自己做)、Kafka(吞吐高但延迟与部署模型不适合设备内实时数据)。答题时把「QoS 可配 + 去中心化 + 自动发现」三个关键词说出来,再补一句为什么不选 MQ。

时序数据项目怎么讲:面试官问「频率多少、数据量多大、有没有断线重连」就是在核对是否真做过。要能报出具体数字与设计取舍:① 指标与频率——例如 N 路传感器、每路 100Hz~1kHz 采样,通道数 × 频率 = 每秒点数,乘上每条记录的字节数得到写入吞吐(比如 32 通道 × 1kHz × 16 字节 ≈ 512KB/s),再乘保存周期算日增存储量;② 存储选型——本地环形缓冲 + 落盘文件 + 时序库(InfluxDB/TDengine)分层的理由,写入要批量、要按时间分区;③ 断线重连——采集端要有本地缓存(环形队列/文件队列)保证断连期间不丢数据,重连后按时间戳补传并去重(服务端按「设备 id + 时间戳」做幂等),连接要有心跳与超时检测、指数退避重连;④ 遇到的问题与解决——典型有三类:时间戳不同步(NTP/统一时基)、高频写入导致的锁竞争与内存增长(无锁队列 + 批量落盘)、以及查询慢(按时间分区 + 降采样预聚合)。把「量级 → 选型 → 问题 → 解决」串起来讲,比罗列技术名词有效得多。

Lambda 与智能指针:Lambda 是编译器生成的匿名函数对象,[捕获列表](参数) -> 返回类型 { 体 };捕获方式有按值 [=]、按引用 [&]、显式 [x, &y]、以及 C++14 的初始化捕获 [p = std::move(ptr)]。要点:按引用捕获的变量不能比闭包活得短(异步回调里捕获局部变量引用是经典悬垂 bug),要长期保存的回调用按值或 shared_ptr 捕获;mutable 才能修改按值捕获的副本;捕获 this 时对象析构后调用会崩(C++17 起可用 [*this] 按值捕获副本);无捕获的 lambda 能隐式转成函数指针。智能指针部分:unique_ptr(独占、零开销、make_unique)、shared_ptr(引用计数、控制块、循环引用要 weak_ptr)、weak_ptr(不增计数,lock() 提升后判空使用);实现上 shared_ptr 的计数是原子的但对象访问不是线程安全的;shared_ptr 通常 16 字节(对象指针 + 控制块指针),make_shared 一次分配更省且缓存更友好,但会延迟对象内存的释放(要等所有 weak 引用消失)。

面试复盘:全场约 40 分钟,按大类校招、面试官没有深挖技术,属于「简历 + 基础 + 一道手撕」的常规组合,原帖作者反馈「没有秒挂」。这类面试的准备重点不是难题,而是把项目讲清楚(尤其是数据指标要能报数)并把常见八股答稳;「有了解我们公司吗」「期望城市」这类问题要提前准备一句话的业务理解与明确的意向城市,这在校招里往往是稳定性评分项。