2018百度云校招面试总结
- 在这个面试体验感很不舒服, 有压力面试的感觉;
- 总结起来人家对我的项目一点不感兴趣, 面后台的岗位都会很难;
现场笔试题
- 树的和为k的所有路径
- 树的先序遍历, 注意到递归结束条件
- 我代码写出来了, 但涂涂改改有点乱, 而且当时自己也不太确定, 就直接给面试官说给他讲思路, 代码应该是错的;
- 这里犯了一个特别大的错误, 就是不够自信, 一不自信就会给面试官的第一印象特别差, 导致后面的面试特别反感, 影响了整个面试过程的体验;
面试官各种问题
- 问我的性格, 优缺点
- Nginx, hash, 红黑树, AVL树, B+, B-树
- 重新总结一下hash, 红黑树, AVL树, B+树, B-树;
- 线程通信机制:
- 条件变量
- 条件变量的实现;
- 线程条件变量原理分析;
- 条件变量本质上是一个全局可访问的flag,所以,线程在调用pthread_cond_wait之前必须先调用pthread_mutex_lock对条件变量加互斥锁;
- pthead_cond_wait函数首先检测当前条件变量的值,如果条件变量为真,线程直接从pthread_cond_wait函数返回,继续执行下面的代码;
- 如果为假,那么线程不具备工作的条件,必须等待,为了不浪费CPU资源,pthread_cond_wait函数让线程进入了休眠状态;
- 为了不阻塞其他线程,让其他线程也可以访问条件变量,pthread_cond_wait函数又释放了互斥锁;
- 但此时进入休眠状态的线程依然位于pthread_cond_wait函数内,执行过程在pthread_cond_wait函数处阻塞;
- 当线程工作的条件具备时,pthread_cond_signal函数负责将条件变量修改为真,同时发信号通知等待的线程;
- 因等待条件变量而进入休眠状态的线程将在pthread_cond_wait函数内被信号唤醒;
- 在pthread_cond_wait函数中, 先释放锁, 再睡眠, 再加锁, 再对条件变量进行检验;
- 线程被唤醒的同时重新获取了互斥锁,并再次对条件变量检测,发现条件变量为真,线程具备了工作的条件;
- pthread_cond_wait函数从阻塞(线程休眠)状态返回,然后线程继续执行下面的代码;
- 线程在完成对全局资源的访问后,释放互斥锁;
- 条件变量机子是将全局标记、线程信号、线程休眠、加锁解锁结合在一起, 主要包含在pthread_cond_wait函数内, 包括:
- 检测条件变量, 为真从函数中返回, 继续执行下一步, 为假则:
- 设置线程等待条件(变量变为真的)信号;
- 让线程进入休眠状态;
- 释放互斥锁;
- 接收到条件(变量变为真的)信号后, 则:
- 唤醒休眠的线程;
- 重新获取互斥锁;
- 重新检验条件变量, 为假, 则继续执行步骤1, 为真则从函数内返回;
- pthread_cond_signal函数的主要工作是负责修改条件变量的值和发送信号提醒等待线程条件变量变成了真值;
- 检测条件变量, 为真从函数中返回, 继续执行下一步, 为假则:
- 条件变量和互斥量结合使用, 互斥锁保护的是两种资源: 条件变量和线程需要访问的全局资源;
- 因为线程在pthread_cond_wait函数内被唤醒后,重新获取了互斥锁,然后才能检测条件变量,条件变量为真,从函数返回后,并没有申请获取其他的互斥锁,就继续对全局资源访问,并在完成访问后只释放了一次互斥锁;
- 共享内存怎么加锁
- shm_ptr是共享内存映射得来的虚拟地址, 用映射的虚拟地址来保存互斥量
- 用信号量来完成互斥的效果
- 文件记录锁
- 自己实现一个原子的自旋锁
- 使用无所结构
- 生产者-消费者模型中的队列,可以使用无锁队列来实现
- 包括共享线程锁、文件锁、使用无锁结构
- 被问得怀疑人生
- gdb调试 core dump文件
- gdb调试coredump使用篇;
- coredump叫作核心转储, 它是进程运行时在突然崩溃的那一时刻的一个内存快照;
- 操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里;
- 这个coredump产生的文件是一个二进制文件;
- 虽然我们知道进程在coredump的时候会产生core文件, 但有时候发现进程虽然core了, 但我们却找不到core文件;
- ulimit -c 可以设置core文件的大小,如果这个值为0.则不会产生core文件,这个值太小,则core文件也不会产生,因为core文件一般都比较大;
- gdb的简单使用教程;
- l 查看源码(list);
- b 加断点(break);
- r 开始运行调试(restart);
- n 下一步(next);
- s 下一步但是会进入子函数();
- p 输出数据(printf);
- gdb 其它常用命令用法 c q b info;
- 多线程调试常用就这三个实用命令
- info threads
- thread id
- set scheduler-locking on/off
- gdb调试coredump使用篇;
- epoll机制怎么实现事件回调的
- 通过epoll_ctl向红黑树添加要被监测的事件时, 会向内核注册回调函数, 当事件活跃的时候会触发中断函数, 调用回调函数, 然后把该活跃的事件添加到双向链表中;
- C++11的四种智能指针, 有缺点
- auto_ptr 已经被C++11弃用了
- shared_ptr
- weak_ptr
- unique_ptr 是为了取代auto_ptr的产物;
- unique_ptr是一个独享所有权的智能指针, 它提供了严格意义上的所有权;
- 拥有它指向的对象;
- 无法进行复制构造, 无法进行复制赋值操作, 即无法使两个unique_ptr指向同一个对象, 但是可以进行移动构造和移动赋值操作;
- 保存指向对象的指针, 当它本身被删除释放的时候, 会使用给定的删除器释放它指向的对象;
- unique_ptr 可以实现如下功能:
- 为动态申请的内存提供异常安全
- 讲动态申请的内存所有权传递给某函数
- 从某个函数返回动态申请内存的所有权
- 在容器中保存指针
- auto_ptr 应该具有的功能
- 迭代器什么时候才会失效
- STL各种容器迭代器失效的时机;
- 标准STL序列容器:vector、string、deque和list;
- 标准STL关联容器:set、multiset、map和multimap。
- 非标准序列容器slist和rope;
- slist是一个单向链表,rope本质上是一个重型字符串
- 非标准关联容器hash_set、hash_multiset、hash_map和hash_multimap;
- 几种标准非STL容器,包括数组、bitset、valarray、stack、queue和priority_queue;
- 值得注意的是,数组可以和STL算法配合,因为指针可以当作数组的迭代器使用;
- vector:
- 当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
- 当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
- 当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
- deque迭代器的失效情况:
- 在deque容器首部或者尾部插入元素不会使得任何迭代器失效。
- 在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
- 在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。
- List/set/map
- 删除时,指向该删除节点的迭代器失效;
- STL中迭代器失效详解;
- vector重新申请内存迭代器就会失效;
- fork(), waitfork();
- 还有好多都忘得差不多了, (~衰~);
- 内存泄漏时, 用户程序吃内存, 把程序内存吃满了会怎么办? 内核程序呢?
- 面试官当时说的是不管是用户还是内核程序, 内核内存管理子系统都会把占用内存的程序kill掉;
- 浅谈Linux的内存管理机制;
- 虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space);
- Linux系统会不时的进行页面交换操作,以保持尽可能多的空闲物理内存,即使并没有什么事情需要内存,Linux也会交换出暂时不用的内存页面, 避免需要时等待分配, 有点未雨绸缪的味道;
- 内核是如何管理内存的;