影石 音视频开发-C++ 二面

1. 你能实习多久,能不能稳定实习 6 个月

2. TCP 丢包之后一般怎么处理

答案:TCP 是可靠传输协议,所以它不会把“丢包”直接暴露给应用层,而是通过确认、重传、滑动窗口这些机制自己处理。最基本的手段是超时重传,也就是发送方在发出数据后等待 ACK,如果超时没收到确认,就认为可能丢包并重传。除此之外还有快速重传。如果发送方连续收到多个重复 ACK,说明某个中间报文段大概率丢了,不必等超时,直接提前重传。在工程上,丢包不只是“重传一下”这么简单,它还会影响 RTT 估计、拥塞控制、发送窗口增长和整体吞吐。如果是在音视频场景里,还要补一句:TCP 虽然可靠,但丢包重传会带来时延抖动,所以实时音视频很多时候更倾向 UDP + 自定义重传、FEC 或者拥塞控制方案,而不是纯 TCP。

3. 讲一下拥塞窗口,怎么调整,有哪些算法

答案:拥塞窗口 cwnd 可以理解成发送方基于网络拥塞状态给自己加的一层流量限制。发送方真正能发多少数据,通常取决于 min(接收窗口, 拥塞窗口)。接收窗口解决的是接收端来不来得及收,拥塞窗口解决的是网络能不能承受。TCP 拥塞控制经典过程包括慢启动、拥塞避免、快速重传和快速恢复。刚开始时通过慢启动快速探测网络能力,cwnd 近似指数增长;达到慢启动阈值后进入拥塞避免,改成线性增长;如果出现丢包,说明网络可能拥塞,就减小窗口。经典算法包括 Tahoe、Reno、NewReno,后面还有 CUBIC、BBR。CUBIC 在 Linux 上很常见,它针对高带宽长时延网络做了更激进的窗口增长;BBR 则不再主要依赖“丢包等于拥塞”这个假设,而是尝试建模带宽和最小 RTT。如果面试官继续追问音视频场景,可以顺手提一下:实时流媒体更关注时延和抖动,很多时候会借鉴 TCP 拥塞控制思想,但不会完全照搬。

4. 进程间 IPC 里最快的通常是什么,共享内存怎么同步

答案:如果只讨论同机 IPC 的纯数据传输效率,共享内存通常是最快的一类方案,因为它避免了多次数据拷贝,多个进程直接看到同一块物理内存。但共享内存快,不代表它“开箱即用”。它只解决了数据共享问题,不解决并发同步问题。同步常见做法包括进程间互斥锁、读写锁、POSIX 信号量、System V 信号量、原子变量、环形队列加序号控制等。如果是单生产者单消费者,通常可以设计成无锁或低锁结构;如果是多生产者多消费者,就要更仔细地处理竞争、缓存一致性和伪共享问题。所以 IPC 里真正难的不是“哪种最快”,而是“哪种在你的访问模式下吞吐高、延迟稳、实现复杂度可控”。

5. 在共享内存上直接分配 vector 会有什么问题

答案:直接把普通 std::vector 放到共享内存里,通常会有问题。核心原因是 vector 内部真正存数据的那块连续内存,默认还是通过当前进程的分配器去申请的,也就是进程自己的堆,不一定在共享内存区域内。这样就会出现一种很尴尬的情况:vector 对象本身放在共享内存里,但它内部的 data 指针指向的是某个进程私有地址空间,其他进程根本没法正确访问。另外即便数据本身也放到共享内存里,普通 STL 容器内部常常依赖绝对地址、默认 allocator、进程内对象语义,跨进程直接共享并不安全。更合理的做法是使用共享内存专用分配器、偏移指针,或者直接自己设计定长数组 / 环形缓冲区结构。如果面试官追问,可以进一步答 Boost.Interprocess 这类库,它就是专门解决这类共享内存容器问题的。

6. 用事件驱动模型实现一个定时器,思路是什么

答案:事件驱动模型下实现定时器,核心思路不是“开一个线程 sleep”,而是把时间事件纳入统一事件循环。通常会维护一个按触发时间排序的数据结构,比如小根堆、时间轮、红黑树。事件循环每次处理 I/O 事件之前,会先看当前最近一个定时器还有多久到期,然后把这个时间作为 epoll_waitpoll/select 的超时时间。如果超时返回或者有其他事件唤醒,就检查哪些定时器到期,把回调执行掉。小根堆适合通用定时器实现,插入和取最近到期元素都比较直接;时间轮更适合大量定时任务且精度要求可控的场景。在音视频开发里,定时器往往会用在心跳、帧调度、超时回收、重传检测、播放时钟同步这些地方。

代码:

#include <iostream>
#include <queue>
#include <vector>
#include <chrono>
#include <thread>
#include <functional>

using namespace std;
using Clock = chrono::steady_clock;

struct TimerTask {
    Clock::time_point expire;
    function<void()> cb;

    bool operator<(const TimerTask& other) const {
        return expire > other.expire; // 小根堆
    }
};

int main() {
    priority_queue<TimerTask> pq;

    pq.push({Clock::now() + chrono::seconds(1), [] {
        cout << "task1 fired\n";
    }});
    pq.push({Clock::now() + chrono::seconds(3), [] {
        cout << "task2 fired\n";
    }});

    while (!pq.empty()) {
        auto now = Clock::now();
        auto next = pq.top().expire;
        if (now < next) {
            this_thread::sleep_for(next - now);
        }
        while (!pq.empty(

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论

相关推荐

03-13 00:04
已编辑
吉林大学 Java
约面的挺突然。。狠下心接了1.自我介绍2.讲讲JAVA的反射3.可以继续讲讲AOP,动态代理[&nbsp;因为讲反射不小心吟唱到了例如AOP的动态代理,但是这块记忆的非常不熟,结果磕磕绊绊&nbsp;]4.项目我看你写了AOP和注解,具体怎么实现滑动窗口限流的[&nbsp;梦到什么说什么,吟唱八股发散千万不要散到自己不熟悉的区域&nbsp;]5.也讲讲为什么另一个项目选择令牌桶,具体流程6.&nbsp;OK,讲讲&nbsp;Redis&nbsp;的数据类型?还有吗?就了解这五种嘛[&nbsp;把5个的基础类型从应用对比到历届底层全都吟唱了一遍。一句还有吗直接没力气了,简历就写了理解5种,别的我是真一点没看TT&nbsp;]7.讲讲Redission分布式锁实现8.这个指数退避怎么实现的9.在这里有考虑去保障幂等性嘛10.这里为什么使用指数退避呢?&nbsp;什么时候用均匀重传[已经晕过去了说不了解,刚说了后就意识到,估计应该说指数退避能缓解压力防止下游服务器雪崩之类的]11.ok,那讲讲JMM12.讲讲RocketMQ如何保证的不丢消息13.讲讲RocketMQ延迟消息原理14.讲讲项目Redis实现会话记忆这一块15.如果ai调用function&nbsp;calling出现幻觉,有考虑怎么解决吗?[&nbsp;不了解,面试官说什么接口幂等化,高危操作人工防护,没在听,感觉人已经飞升了TT&nbsp;]16.mcp了解嘛?和function&nbsp;calling有什么区别[&nbsp;依旧不了解,只能说了个前者规范架构抽象解耦,后者耦合高只能算个工具调用]17.AI生成代码的代码质量怎么保障,那平时如何review的呢18.算法。lc215&nbsp;&nbsp;数组中最大第k个元素19.打算考研还是本科就业20.反问1️⃣有哪里不足,有哪些需要提高的部分。[主要说知识广度不够,多刷算法,让我别太紧张]2️⃣部门业务会做什么人生第二次面试。感觉大厂面试官的气场压力很大应该凉了不过这次面试非常锻炼心态,多面试,多面试。
冰炸橙汁_不做oj版:redis除了五种基本数据类型,其他的几种还是要掌握一下的,挺常用
点赞 评论 收藏
分享
评论
点赞
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务