字节跳动 C++面经总结及解析 第一期

0.我们的公众号:寻常几盏灯火,欢迎前往,更多面经内推,祝您早日拿到offer奥~

1.进程和线程的区别,有了进程为什么还要有线程

2.进程的资源、线程的资源

3.多线程怎么同步,多线程竞争怎么解决

4.进程通信

5.线程之间的通信方式

6.一次完整的http请求过程

7.http和https区别,哪个更快

8.https加密过程

9.HTTP和TCP的区别

10.DNS域名解析过程,用到了什么协议(UDP),最后获得IP地址就能怎样呢(就可以识别在网络中的机器)

11.TCP和UDP区别以及各自使用场景,UDP不可靠的话那为什么咱们现在视频这么流畅,是依靠什么

12.TCP拥塞控制

13.udp可以实现的功能

14.如何使UDP达到和TCP相同的效果

15.new malloc区别

16.new/delete,malloc/free,delete/delete[] 

17.static关键字

18.static应用场景

19.虚函数的作用和底层实现(实现多态,虚表 虚表指针)

20.哪些函数不能是虚函数,构造函数为什么不行

题目解析

1.

区别:

1. 进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位)

2. 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。

而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

3. 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

4. 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

为什么:

进程属于在CPU和系统资源等方面提供的抽象,能够有效提高CPU的利用率。

线程是在进程这个层次上提供的一层并发的抽象:

(1)能够使系统在同一时间能够做多件事情;

(2)当进程遇到阻塞时,例如等待输入,线程能够使不依赖输入数据的工作继续执行

(3)可以有效地利用多处理器和多核计算机,在没有线程之前,多核并不能让一个进程的执行速度提高

2.

一、堆与栈

堆: 是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

栈:是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe的。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

二、其他

线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。

进程拥有这许多共性的同时,还拥有自己的个性。有了这些个性,线程才能实现并发性。这些个性包括:

1.线程ID

每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标识线程。

2.寄存器组的值

由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线程切换到另一个线程上时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程在被重新切换到时能得以恢复。

3.线程的堆栈

堆栈是保证线程独立运行所必须的。线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程必须拥有自己的函数堆栈,使得函数调用可以正常执行,不受其他线程的影响。

4.错误返回码

由于同一个进程中有很多个线程在同时运行,可能某个线程进行系统调用

后设置了errno值,而在该线程还没有处理这个错误,另外一个线程就在此时

被调度器投入运行,这样错误值就有可能被修改。

所以,不同的线程应该拥有自己的错误返回码变量。

5.线程的信号屏蔽码

由于每个线程所感兴趣的信号不同,所以线程的信号屏蔽码应该由线程自

己管理。但所有的线程都共享同样的信号处理器。

6.线程的优先级

由于线程需要像进程那样能够被调度,那么就必须要有可供调度使用的参

数,这个参数就是线程的优先级。

3.

C++线程同步的四种方式:互斥锁,条件变量,读写锁,信号量

5.

1. 使用全局变量 

主要由于多个线程可能更改全局变量,因此全局变量最好声明为volatile

2. 使用消息实现通信 

在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程默认自带消息队列和消息循环,工作线程需要手动实现消息循环),因此可以采用消息进行线程间通信sendMessage,postMessage。 

1)定义消息#define WM_THREAD_SENDMSG=WM_USER+20; 

2)添加消息函数声明afx_msg int OnTSendmsg();  

3)添加消息映射ON_MESSAGE(WM_THREAD_SENDMSG,OnTSM)  

4)添加OnTSM()的实现函数; 

5)在线程函数中添加PostMessage消息Post函数

3. 使用事件CEvent类实现线程间通信 

Event对象有两种状态:有信号和无信号,线程可以监视处于有信号状态的事件,以便在适当的时候执行对事件的操作。 

1)创建一个CEvent类的对象:CEvent threadStart;它默认处在未通信状态;  

2)threadStart.SetEvent();使其处于通信状态;  

3)调用WaitForSingleObject()来监视CEvent对象

6.

一个完整的HTTP过程包括建立连接、数据传输、断开连接等七个步骤。

1. TCP建立连接 

HTTP协议是基于TCP协议来实现的,因此首先就是要通过TCP三次握手与服务器端建立连接,一般HTTP默认的端口号为80;

2. 浏览器发送请求命令 

在与服务器建立连接后,Web浏览器会想服务器发送请求命令

3. 浏览器发送请求头消息 

在浏览器发送请求命令后,还会发送一些其它信息,最后以一行空白内容告知服务器已经完成头信息的发送;

4. 服务器应答 

在收到浏览器发送的请求后,服务器会对其进行回应,应答的第一部分是协议的版本号和应答状态码;

5. 服务器回应头信息 

与浏览器端同理,服务器端也会将自身的信息发送一份至浏览器

6. 服务器发送数据 

在完成所有应答后,会以Content-Type应答头信息所描述的格式发送用户所需求的数据信息

7. 断开TCP连接 

在完成此次数据通信后,服务器会通过TCP四次挥手主动断开连接。但若此次连接为长连接,那么浏览器或服务器的头信息会加入keep-alive的信息,会保持此连接状态,在有其它数据发送时,可以节省建立连接的时间。

7.

Http更快。

8.

https证书加密的第一步是认证服务器。

一些主流浏览器会内置一个受信任的CA机构列表,并会保存相关CA机构的https证书。当用户在访问部署了https证书的网站时,服务器会提供经CA机构颁发的https证书,如果认证该服务器证书的CA机构是存在于浏览器的受信任CA机构列表当中,并且该https证书中的所有信息均与当前证在访问的网站所有信息一致,那么浏览器就会认为服务端是可信的,并从https证书中取得公钥(也就是CSR文件),用于后面的流程。

https证书加密的第二步是协商会话秘钥。

在服务器认证完获取公钥之后,利用公钥与服务器进行加密通信,协商出两个会话秘钥,用于加密客户端和加密服务端互发数据时的会话秘钥。这个秘钥是随机生成的,每一次协商产生的结果都不一样,所以安全性也是比较高的。

https证书加密的第三步是加密传输。

当客户端和服务器端都拥有了协商的会话密钥之后,进行数据传输时,都是以密文的方式进行传输。这样的传输方式,保证了数据的私密性和完整性,再也不用担心数据在传输过程中被第三者窃取和篡改了。

https证书加密完成这三步,就表示很完美的进行了一次数据加密传输。只要你申请的https证书是由受信任的CA机构(比如Symantec、Geotrust、Comodo以及RapidSSL等)颁发的,都可以保障网络的基本安全。

9.

TCP是传输层协议,定义数据传输和连接方式的规范。握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

HTTP 超文本传送协议(Hypertext Transfer Protocol )是应用层协议,定义的是传输数据的内容的规范。

HTTP协议中的数据是利用TCP协议传输的,特点是客户端发送的每次请求都需要服务器回送响应,它是TCP协议族中的一种,默认使用 TCP 80端口。

10.

UDP

就可以识别在网络中的机器

11.

1、面向连接VS无连接

TCP建立一个连接需要3次握手IP数据包,断开连接需要4次握手。另外断开连接时发起方可能进入TIME_WAIT状态长达数分钟(视系统设置,windows一般为120秒),在此状态下连接(端口)无法被释放。

UDP不需要建立连接,可以直接发起。

2、可靠VS不可靠

TCP利用握手、ACK和重传机制,udp没有。

(1)校验和(校验数据是否损坏);

(2)定时器(分组丢失则重传);

(3)序列号(用于检测丢失的分组和重复的分组);

(4)确认应答ACK(接收方告知发送方正确接收分组以及期望的下一个分组);

(5)否定确认(接收方通知发送方未被正确接收的分组);

(6)窗口和流水线(用于增加信道的吞吐量)。(窗口大小:无需等待确认应答而可以继续发送数据的最大值)

3、有序性

TCP利用seq序列号对包进行排序,udp没有。

4、面向字节流vs面向报文

(1)面向报文

面向报文的传输方式是应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。因此,应用程序必须选择合适大小的报文。若报文太长,则IP层需要分片。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这也就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。(一个upd的最大报文长度2^16-1-20-8,20是ip报文头,8是udp报文头)

(2)面向字节流

面向字节流的话,虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序看成是一连串的无结构的字节流。TCP有一个缓冲,当应用程序传送的数据块太长,TCP就可以把它划分短一些再传送。如果应用程序一次只发送一个字节,TCP也可以等待积累有足够多的字节后再构成报文段发送出去。

5、tcp有流量控制,udp没有

6、tcp的头部比20bytes,udp8byres

TCP应用场景:

效率要求相对低,但对准确性要求相对高的场景。因为传输中需要对数据确认、重发、排序等操作,相比之下效率没有UDP高。举几个例子:文件传输(准确高要求高、但是速度可以相对慢)、接受邮件、远程登录。

UDP应用场景:

效率要求相对高,对准确性要求相对低的场景。举几个例子:QQ聊天、在线视频、网络语音电话(即时通讯,速度要求高,但是出现偶尔断续不是太大问题,并且此处完全不可以使用重发机制)、广播通信(广播、多播)。

UDP 要保证可靠,就依赖于重传

12.

1.慢开始

2.拥塞控制

3.快重传

4.快恢复

13.

简单的聊天功能、在线视频、网络语音电话

14.

UDP要达到TCP的功能就必须实现拥塞控制的功能

15.

1、malloc与free是c++/c语言的标准函数,new/delete是C++的运算符。

2、他们都可用于申请动态内存和释放内存。new/delete比malloc/free更加智能,其实底层也是执行的malloc/free。为啥说new/delete更加的智能?因为new和delete在对象创建的时候自动执行构造函数,对象消亡之前会自动执行析构函数。

既然new/delete的功能完全覆盖了malloc和free,为什么C++中不把malloc/free淘汰出局呢?因为c++程序经常要调用c函数,而c程序智能用malloc/free管理动态内存。

3、new返回指定类型的指针,并且可以自动计算出所需要的大小。如 :

int *p; p = new int; //返回类型为int*类型,大小为sizeof(int);

int *pa; pa = new int[50];//返回类型为int *,大小为sizeof(int) * 100;

malloc必须用户指定大小,并且默然返回类型为void*,必须强行转换为实际类型的指针。

16.

1、new/delete是C++的操作符,而malloc/free是C中的函数。

2、new做两件事,一是分配内存,二是调用类的构造函数;同样,delete会调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。

3、new建立的是一个对象,而malloc分配的是一块内存;new建立的对象可以用成员函数访问,不要直接访问它的地址空间;malloc分配的是一块内存区域,用指针访问,可以在里面移动指针;new出来的指针是带有类型信息的,而malloc返回的是void指针。

4、new/delete是保留字,不需要头文件支持;malloc/free需要头文件库函数支持。

17.

1.先来介绍它的第一条也是最重要的一条:隐藏。(static函数,static变量均可)

当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。

2.static的第二个作用是保持变量内容的持久。(static变量中的记忆功能和全局生存期)

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。

3.static的第三个作用是默认初始化为0(static变量)

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。

4.static的第四个作用:C++中的类成员声明static(有些地方与以上作用重叠)

在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:

(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。 

(2)不能将静态成员函数定义为虚函数。 

(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊 ,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。

(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X W indow系统结合,同时也成功的应用于线程函数身上。 (这条没遇见过) 

(5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问 时间,节省了子类的内存空间。 

(6)静态数据成员在<定义或说明>时前面加关键字static。 

(7)静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误) 

(8)静态成员初始化与一般数据成员初始化不同:

初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;

初始化时不加该成员的访问权限控制符private,public等;  

初始化时使用作用域运算符来标明它所属类;

所以我们得出静态数据成员初始化的格式:

<数据类型><类名>::<静态数据成员名>=<值>

(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。

18.

1. 出现在类体外的函数定义不能指定关键字static;//static 是申明时候用的

2. 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

非静态成员函数可以任意地访问静态成员函数和静态数据成员;

3. 静态成员函数不能访问非静态成员函数和非静态数据成员;

4. 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

5. 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:

<类名>::<静态成员函数名>(<参数表>) 

6. 调用类的静态成员函数。

19.

C++中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在派生类中对基类定义的虚函数进行重写时,需要再派生类中声明该方法为虚方法。

C++虚函数的底层实现原理

参考:https://blog.csdn.net/u011000290/article/details/50498683

20.

常见的不能声明为虚函数的有:普通函数(非成员函数)、静态成员函数、内联成员函数、构造函数、友元函数。

为什么:

1.调用虚函数需要访问虚表,构造函数在调用前根本不存在虚表,这带来了先有鸡还是先有蛋的问题;

2.多态是根据指针指向的具体对象类型调用对应的方法,前提当然是这个对象是已经构建出来了;

3.构造函数是定义一个对象时自动调用的,用户不能自己调用构造函数,所以没必要是虚函数;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351