2019春招CVTE面试(1)

突如其来的电话面试,以为面试没去凉了,但还好没被放弃,^_^

问的比较基础,但好多答得也挺混乱,所以赶紧找找答案,面试官人很nice,紧张了

1.死锁及解决方法
当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。
按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁。但总有些时候是无法预知的。
另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(注:加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。
此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。
死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。
当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。
当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。如线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1。
那么当检测出死锁时,这些线程该做些什么呢?
一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。但是同超时类似,不能从根本上减轻竞争。
一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。
当时举得例子是人工抢票,当时只有票这一个资源,每个线程都只需要一把锁,预定票的人支付之前都不会解锁,不适用这个案例。
并发操作最易导致死锁
假设有一个操作要交换同一个类的两个实例的内容,为了交换操作不被并发修改影响,我们需要锁定这两个实例内部的mutex。但是,如果选定一个固定的顺序来锁定mutex(线锁定第一个参数指定对象的mutex,再锁定第二个参数指定对象的mutex)恰恰适得其反,会导致死锁。

针对这种情况,我们需要使用C++11标准库的std::lock操作来解决这个问题。lock函数可以接受两个或者多个mutex以避免死锁。
转载[C++11 并发编程] 07 - Mutex 死锁
https://blog.csdn.net/yamingwu/article/details/47682261
作者:yamingwu


2.udp与tcp的区别,tcp为什么有三次握手,四次挥手
TCP面向有连接,可靠的流协议。保证两端通讯主机之间的通信可达,可以处理丢包、乱序等异常,可以有效利用带宽、缓解网络拥堵。
UDP 不提供复杂的控制机制,利用 IP 提供面向无连接的通信服务,随时都可以发送数据,处理简单且高效,经常用于以下场景:
包总量较小的通信(DNS、SNMP)
视频、音频等多媒体通信(即时通信)
1.TCP 是面向连接的,UDP 是面向无连接的;故 TCP 需要建立连接和断开连接,UDP 不需要。
2.TCP 是流协议,UDP 是数据包协议;故 TCP 数据没有大小限制,UDP 数据报有大小限制(UDP 协议本身限制、数据链路层的 MTU、缓存区大小)。
3.TCP 是可靠协议,UDP 是不可靠协议;故 TCP 会处理数据丢包重发以及乱序等情况,UDP 则不会处理。

客户端client的整个过程
2019春招CVTE面试(1)_第1张图片

服务器server端的整个过程

2019春招CVTE面试(1)_第2张图片

这里需要说明的是FIN_WAIT,整个过程有两次FIN_WAIT即4MSL(报文段最大生存时间)

这个问题没有答基本算正确,前面的区别只回答了面向连接和无连接以及可靠不可靠

3如何判断单链表是否有环

定义一个fast指针和slow指针,一个走两步,一个走一步,向后遍历如果有环,两者必然相遇,扩充,求入环结点。

https://www.jianshu.com/p/ef71e04241e4

当时回答没有提到了用指针,但还是想着编序号,诶。

4.堆和栈的区别,面向对象程序设计特点,虚函数和纯虚函数的不同和作用

除了封装,继承,多态,最重要它是一个非过程,是将控制权转移到数据上,是围绕着“正在影响了谁”而不是“正在发生什么”。

堆和栈的区别:
  一、堆栈空间分配区别:
  1、栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
  2、堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
  二、堆栈缓存方式区别:
  1、栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
  2、堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
  三、堆栈数据结构区别:
  堆(数据结构):堆可以被看成是一棵树,如:堆排序;
  栈(数据结构):一种先进后出的数据结构。

虚函数为了重载和多态的需要,在基类中是有定义的,即便定义是空,所以子类中可以重写也可以不写基类中的此函数!

纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数!

https://blog.csdn.net/iceminer/article/details/12026377

补充虚函数表,解答了我多年疑问鸭

https://blog.csdn.net/haoel/article/details/1948051/

还有关于typedef函数指针

http://www.cnblogs.com/hwl1023/p/6590213.html

只答了区别一,emmm,我竟然答了派生,想打死自个o(╥﹏╥)o,虚函数和纯虚函数倒是回答到了点子上。

5.排序之快速排序(改进)

1 问题降到一定规模时,改用插入排序

2 中轴元素的选取

3 分成3堆,一方面避免相同元素这种情况,另一方面也可以降低子问题的规模。这个感觉有点像DFS中寻找剪枝条件来降低搜索规模一样。

https://blog.csdn.net/u013861473/article/details/27385507

关于排序

https://www.cnblogs.com/edwinchen/p/4782179.html

还问了我了不了解c++11,还是要多看书啊。

你可能感兴趣的:(面试)