面灵AI→

华为 ICT 三轮面经:IAP 升级与防变砖、Modbus RTU、线程池手撕

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

《面试题目》

一面

  1. 进程和线程的区别是什么?
  2. 用过哪些设计模式?
  3. 内核移植相关的问题。
  4. 堆和栈的内存有什么区别?malloc 是怎么分配内存的?
  5. 回顾一下笔试:挑一道题讲一下你的思路。
  6. 手撕:实现一个线程池。

二面

  1. 课题项目的算法设计与实现,以及运行它的物理环境是怎样的?
  2. IAP 相关的内存划分是怎么做的?
  3. 如何防止固件被恶意刷写?
  4. 如何保证升级过程不变砖?还可以从哪些方面提升安全性?
  5. Modbus RTU 协议相关的问题。
  6. 第一段实习里的底层驱动相关问题。
  7. 手撕:无重复字符的最长子串。

三面

  1. 实习中遇到的难题是什么?
  2. 有没有遇到过什么挫折?
  3. 有没有遇到过比较难沟通的场景?
  4. 你的优缺点分别是什么?

《参考解析》

IAP 升级这组题是华为嵌入式面的核心考点,答法要落成「分区 + 校验 + 回滚」三段。 内存划分上,Flash 至少分 Bootloader、App A、App B(或 App + 备份区)、参数区;Bootloader 只负责「决定从哪个分区启动」和「搬运/校验升级包」,尽量小且升级过程中不改,这样才谈得上不变砖。防恶意刷写要分层次:传输层做签名(升级包用私钥签名、设备用公钥验签),存储层做完整性校验(CRC32 或 SHA-256 摘要存在参数区),启动层做版本与防回滚(记录版本号和计数器,拒绝降级到已知漏洞版本),再加一层调试口保护(关闭未授权的 SWD/JTAG,或用读保护 + 唯一密钥)。防变砖的关键是「双分区 + 原子切换」:新固件写到备份区并校验通过后,只把参数区里的「启动标记」改成指向新分区(一次原子写),启动失败则由 Bootloader 计数回退到旧分区;升级中途掉电时,标记还没改,设备仍然启动旧固件。再提升安全性可以加「安全启动链」(Bootloader 验 App、App 验外设固件)与「差分升级 + 断点续传」,减少升级包体积和失败概率。

「进程 vs 线程」在嵌入式语境下要带出 RTOS。 进程有独立地址空间,线程共享进程空间、只有独立栈和寄存器上下文;RTOS 里的「任务」更接近线程,切换开销小、共享全局变量,所以必须靠信号量/互斥量保护临界区,且要注意优先级反转。malloc 这题要答实现思路:从堆区按块管理,维护空闲链表,分配时找合适大小的块(首次适配/最佳适配),可能拆分;释放时合并相邻空闲块防碎片。嵌入式里更常见的追问是「为什么很多项目禁用动态内存」——碎片不可预测、分配时间不确定,实时系统里通常用静态内存池替代。

线程池手撕的评分点是「任务队列 + 条件变量 + 优雅退出」。 最小实现是一个任务队列(std::queue<std::function<void()>>)、一把互斥锁、一个条件变量、N 个工作线程;工作线程循环「加锁 → 等队列非空或退出标志 → 取任务 → 解锁 → 执行」。要主动讲三点:一是虚假唤醒要用 while 而不是 if 判断条件;二是退出时要先置停止标志再 notify_all,让所有线程醒来后退出循环并 join,否则主线程会卡在析构;三是任务队列要有上限,满了之后是阻塞生产者还是拒绝,取决于业务(拒绝要返回明确错误,别静默丢弃)。无重复字符最长子串那题用滑动窗口 + 哈希记录字符最后位置,注意「左指针只能右移不能回退」这个细节。

三面全是行为题,答法要有「具体场景 + 我的动作 + 可验证结果」。 挫折题别选「我没遇到什么挫折」,也别选纯粹的外部不幸;选一个自己能复盘的技术或协作挫折,说清楚当时的误判、后来怎么发现、改了什么做法。难沟通的场景要体现「先把对方的真实诉求问出来,再对齐方案」,而不是「我说服了他」。优缺点题里,缺点最好是一个真实的、已经在改的短板(比如「我一开始不太主动同步进度,后来改成每天固定时间发一条进展」),避免用「我太追求完美」这种套话。这位同学最后提到面评 2A1B、第一批报批可能赶不上,也说明了华为的节奏:三面通过不等于 offer,后面还有报批与池子排序,等待期可以继续保温沟通但要留好备选。