拼多多 客户端开发-C++ 一面(暑期)
1. 阻塞和非阻塞有什么区别
答案:阻塞和非阻塞说的是一个调用在资源暂时不可用时,当前线程会不会被挂起等待。阻塞调用在条件不满足时会让线程睡眠,直到数据就绪、锁可用或者事件发生后再返回。非阻塞调用在条件不满足时会立刻返回,不会把线程卡住,调用方需要自己决定是重试、轮询还是交给事件驱动框架处理。比如 socket 读操作,如果是阻塞模式,没有数据时线程会一直等;如果是非阻塞模式,没有数据时通常返回 EAGAIN 或 EWOULDBLOCK。这里要注意,非阻塞不等于异步,异步强调的是结果不是在当前调用栈里直接拿到,而是后面以通知、回调或 future 的形式回来。
代码:
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
int main() {
int fd = socket(AF_INET, SOCK_STREAM, 0);
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
close(fd);
return 0;
}
2. 你这个同步和阻塞有什么关系吗
答案:同步和阻塞不是一个维度。同步关注的是调用发出去之后,结果是不是要在当前执行流里等到;阻塞关注的是线程会不会被挂起。同步阻塞很好理解,比如阻塞式 read,线程一直等到读到数据才返回。同步非阻塞也常见,比如非阻塞 socket 配合循环检查或者 epoll,当前调用没有把线程睡死,但结果还是要由当前流程继续处理。异步阻塞这个说法在工程里不常单独提,通常提异步时,强调的是提交任务和获取结果分离。所以面试里如果追问这个,最好把“调用模型”和“线程状态”分开讲。
3. MySQL 你用的是哪个版本,版本差异一般关注什么
答案:如果真实项目里没有严格卡版本,回答时通常可以说用的是 MySQL 8.x,日常关注过 5.7 和 8.0 的一些差异。版本差异最常见的关注点包括默认字符集、认证插件、执行器优化、窗口函数、CTE、JSON 能力、数据字典和索引统计信息等。比如 MySQL 8.0 引入了窗口函数和公用表表达式,很多复杂查询写法会更自然;默认认证插件也和以前不一样,可能影响客户端连接。如果项目里是老系统,也可能长期停在 5.7,这时候更重要的是知道线上为什么不敢轻易升级,比如兼容性、驱动依赖、主从架构和变更风险。
4. 用过 MySQL 衍生出来的其他数据库吗
答案:比较常见的回答可以是接触过 MariaDB 或 TiDB。MariaDB 和 MySQL 有较强的兼容性,但在存储引擎、功能扩展和社区路线方面有差异。TiDB 虽然 SQL 层兼容 MySQL 协议,但本质上是分布式数据库,底层存储、事务实现、扩缩容和执行计划都和单机 MySQL 很不一样。如果面试官继续追问,重点通常会落在“为什么要从 MySQL 迁到这些方案”,比如单机容量瓶颈、分库分表复杂、强一致事务和在线扩容需求。
5. Git 怎么对比两个分支之间有什么不同,用过其他版本控制器吗
答案:对比两个分支最常见的是看提交差异和代码差异。看提交差异可以用 git log branchA..branchB,看代码差异可以用 git diff branchA..branchB。如果想看某个文件在两个分支上的不同,也可以直接指定文件路径。另外 git diff --name-only 可以快速看哪些文件变了。其他版本控制器如果没实际用过,不建议硬编,可以说了解过 SVN 的集中式版本管理思路,但日常主要还是 Git。如果追问团队协作,通常还会连着问 rebase、cherry-pick、冲突解决和回滚策略。
代码:
git log master..feature git diff master..feature git diff master..feature -- src/main.cpp git diff --name-only master..feature
6. 协程了解吗,协程和线程的区别是什么
答案:协程本质上是一种用户态的轻量级执行单元,它能在函数执行到一半时主动挂起,并在之后从挂起点恢复。和线程相比,协程切换通常不需要陷入内核,切换成本更低,适合大量高并发但计算不重、等待多的场景。线程是内核调度单位,能真正并行跑在多个 CPU 核上;协程更多是把并发控制权交给用户态调度器,本身不一定并行。如果协程内部遇到阻塞系统调用,没有配套的非阻塞 IO 或调度器,就可能把整个线程卡住。所以协程不是线程的完全替代,更像是高并发场景下改善编程模型和降低调度开销的一种手段。
7. Linux 系统下查看当前进程占用多少 CPU 用什么命令
答案:常用的是 top、htop、ps。如果要看某个进程当前 CPU 使用率,可以用 top -p pid 或者 ps -p pid -o %cpu,cmd。如果想持续采样并观察线程级别,还可以用 top -H -p pid。进一步分析 CPU 热点时,通常会结合 perf top、perf record、perf report 看函数级别开销。真正工程排查里,一般不会停留在“CPU 高不高”,还会看是用户态高、系统态高,还是线程忙等、锁竞争、GC、IO 抖动。
代码:
top -p 1234 ps -p 1234 -o pid,ppid,%cpu,%mem,cmd top -H -p 1234 perf top -p 1234
8. 如何杀掉一个进程
答案:最常见的是 kill pid,默认发送的是 SIGTERM,意思是通知进程正常退出。如果进程不响应,再用 kill -9 pid 发送 SIGKILL,由内核强制终止。但线上排查时不建议一上来就 kill -9,因为它不给进程清理资源和落日志的机会。如果是按名字杀进程,可以用 pkill 或 killall,但要小心误伤。更成熟一点的答法是:先看进程状态、打开文件、线程堆栈和日志,再决定优雅退出还是强杀。
代码:
kill 1234 kill -15 1234 kill -9 1234 pkill myserver
9. RAII 是什么
答案:RAII 是 Resource Acquisition Is Initialization,意思是资源获取即初始化。核心思想是把资源的获取和释放绑定到对象生命周期里:构造时拿资源,析构时释放资源。它不只是管理内存,也可以管理锁、文件、socket、线程句柄、数据库连接等。RAII 在 C++ 里非常重要,因为它能天然处理异常路径和提前返回路径,避免资源泄漏。像 lock_guard、unique_ptr、文件封装类,本质上都体现了 RAII 思想。
代码:
#include <mutex> using namespac
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.