面经链接:https://www.nowcoder.com/discuss/653930322421108736?sourceSSR=search
1.线程、进程、协程都是什么 有什么区别
特性 | 线程 | 进程 | 协程 |
---|---|---|---|
定义 | 进程中的轻量级子任务,共享进程的内存空间和资源。 | 操作系统中资源分配的基本单位,具有独立的内存空间。 | 用户态的轻量级任务切换,控制由用户代码管理。 |
内存空间 | 共享同一进程的内存空间,彼此之间无隔离。 | 拥有独立的内存空间,进程之间互相隔离。 | 共享同一线程的内存空间,不同协程之间可以共享数据。 |
创建开销 | 开销较小,创建和切换速度快。 | 创建和上下文切换开销较大,需要操作系统内核介入。 | 开销极小,切换非常快,因为在用户态中完成。 |
切换机制 | 由操作系统调度器在内核态进行切换。 | 由操作系统调度器在内核态进行切换。 | 由用户代码显式调度,在用户态进行切换。 |
并发性 | 支持并发执行,多线程可利用多核 CPU 资源。 | 支持并行和并发执行,不同进程可在多核上并行运行。 | 支持并发执行,但依赖于线程的执行,无法真正并行。 |
通信方式 | 通过共享内存直接通信,也可以使用互斥锁、条件变量等。 | 通过进程间通信(IPC)机制,如管道、消息队列、共享内存等。 | 直接共享数据结构,或通过消息传递。 |
安全性 | 由于共享内存,不当的操作可能导致数据竞争和安全问题。 | 进程间隔离较好,安全性较高,但通信较复杂。 | 用户态管理,容易发生不当使用导致的死锁或资源泄露。 |
使用场景 | 多任务处理、高并发场景,如服务器处理多用户请求。 | 独立应用程序、任务隔离、稳定性要求高的场景。 | 高效 IO 操作、协作式任务切换,如异步编程、事件驱动。 |
2.线程之间的通信
通信方式 | 描述 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
共享内存 | 多个线程共享同一块内存,线程可以通过访问这块内存来交换数据。 | 快速,无需内核参与 | 需要手动管理同步,容易出现竞态条件 | 大量数据传输,高性能场景 |
信号量 | 使用计数器来控制对共享资源的访问,确保多个线程之间互斥访问资源。 | 简单有效的同步机制 | 容易产生死锁,复杂度增加 | 资源有限,需严格控制访问的场景 |
互斥锁 | 互斥锁确保一次只有一个线程能够访问共享资源,其他线程需要等待锁释放。 | 提供线程安全的资源访问 | 可能导致死锁,特别是在锁的管理不当时 | 需要同步访问共享资源的场景 |
条件变量 | 线程可以等待某个条件成立,然后继续执行。条件变量通常与互斥锁配合使用。 | 支持线程等待特定事件发生 | 使用较复杂,需要与其他同步原语结合 | 需要线程等待特定条件的场景 |
消息队列 | 线程之间可以通过消息队列发送和接收消息,消息可以是任意数据类型。 | 线程之间解耦,安全的消息传递方式 | 性能相对较低,适合较小数据量的传输 | 不同线程之间的消息传递 |
管道 | 管道是一个字节流,用于线程之间或进程之间的通信,数据通过管道传输。 | 简单易用,适合串行通信 | 性能相对较低,数据流只能单向传输 | 简单的线性数据通信 |
套接字 | 通常用于进程间通信,但也可以用于同一主机上的线程间通信,基于网络协议传输数据。 | 通用性强,可用于跨主机的通信 | 性能开销大,配置较为复杂 | 需要支持跨主机通信的场景 |
事件 | 通过触发事件,唤醒等待该事件的线程。事件通常在操作系统层面实现。 | 简化了线程间的同步,易于使用 | 易引起复杂的状态管理 | 需要通过事件驱动线程操作的场景 |
线程局部存储 | 每个线程都有自己独立的存储区域,不与其他线程共享。 | 无需同步,避免了竞态条件 | 只能在单线程中使用,不适合线程间直接通信 | 每个线程需要独立状态信息的场景 |
3.进程的通信方式
通信方式 | 描述 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
管道 (Pipe) | 单向通信方式,数据通过内存中的管道在父子进程或兄弟进程间传递。 | 简单易用,系统开销小 | 只能单向通信,数据流顺序访问,不能跨越无亲缘关系的进程 | 父子进程之间的小规模数据传输 |
命名管道 (FIFO) | 管道的扩展,允许无亲缘关系的进程之间通信,通过文件系统中的路径名标识。 | 支持无亲缘关系的进程间通信 | 需要额外的文件系统支持,仍然是半双工(单向) | 不相关进程之间的小规模数据传输 |
消息队列 (Message Queue) | 基于消息传递的通信机制,进程可以将消息放入队列,另一个进程从队列中读取。 | 支持有优先级的消息传递,线程安全 | 需要管理消息队列的长度和大小,可能存在消息积压 | 需要进程间解耦,消息传递的场景 |
共享内存 (Shared Memory) | 进程之间共享一块内存区域,所有进程可以直接访问这块内存。 | 速度快,适合大数据量传输 | 需要手动管理同步,容易产生竞态条件 | 高效、大量数据传输的场景 |
信号量 (Semaphore) | 用于控制对共享资源的访问,常用于进程同步。 | 简单有效的同步机制 | 编程复杂度较高,容易产生死锁 | 控制对共享资源的并发访问 |
套接字 (Socket) | 可以用于本地或网络通信,通过IP地址和端口进行标识,支持跨主机的通信。 | 通用性强,支持不同设备间的通信 | 配置复杂,涉及网络编程,可能产生较高的性能开销 | 网络通信和跨机器通信的场景 |
信号 (Signal) | 用于通知进程发生了异步事件,进程可以处理信号来执行相应操作。 | 简单、系统级别支持 | 信号类型有限,且只能传递少量信息,容易产生竞争条件 | 异步事件通知,简单的进程控制 |
内存映射 (Memory Mapped Files, mmap) | 进程可以将文件或其他对象映射到内存地址空间,多个进程可以共享同一块映射的内存。 | 速度快,适合读写大型文件或共享数据 | 需要手动同步数据,映射的内存受文件系统限制 | 高效文件操作和大规模数据共享的场景 |
匿名管道 (Anonymous Pipe) | 类似于普通管道,但只能在具有亲缘关系的进程间使用。 | 无需文件系统支持,系统开销较小 | 只能在亲缘关系的进程间使用 | 父子进程或兄弟进程间的小数据传输 |
D-Bus | 高层次的进程间通信机制,特别是在桌面环境下广泛使用,用于应用程序之间的通信。 | 易于使用,高层次API,适用于桌面环境 | 需要依赖特定的框架,性能不如低级别IPC方式 | 桌面应用程序间的通信 |
远程过程调用 (Remote Procedure Call, RPC) | 允许进程在另一台计算机上执行代码,通过网络进行进程间通信。 | 跨网络通信,实现复杂的分布式系统 | 实现复杂,涉及网络通信和分布式系统 | 分布式系统、跨网络进程间通信 |
4.HTTP是怎么完成通信的
HTTP通信通过请求-响应模型完成:
- 客户端请求:客户端(如浏览器)向服务器发送HTTP请求,指定方法(如GET、POST)和目标资源的URL。
- 服务器响应:服务器接收请求后处理,并返回一个HTTP响应,包含状态码、响应头和可选的响应内容(如网页、数据等)。
- 传输结束:客户端接收响应并根据内容显示或处理数据。通信结束后,连接可以关闭或重用。
5.TCP的三次握手, 为什么是三次不是两次
TCP三次握手是建立连接的过程:
客户端发送SYN:客户端向服务器发送一个SYN报文,请求建立连接。
服务器回应SYN-ACK:服务器收到后,回应一个SYN-ACK报文,表示同意并确认收到请求。
客户端发送ACK:客户端收到SYN-ACK后,再发送一个ACK报文,确认连接建立。
为什么是三次不是两次?
三次握手确保双方都能确认彼此的接收能力和发送能力正常工作。两次握手可能导致“旧的连接请求”被误处理为新连接,造成连接错误。三次握手可以避免这种问题,确保连接是可靠的。
6.HTTPS通信方式是什么,什么是TLS/SSL?
HTTPS是基于HTTP的安全通信协议,通过加密数据来确保传输的安全性。它使用TLS/SSL协议来加密通信内容。
TLS/SSL(传输层安全/安全套接字层)是用于加密网络通信的协议。TLS是SSL的升级版,它们通过证书验证服务器身份,使用对称加密保护数据传输的机密性,并通过消息摘要确保数据完整性。
HTTPS通过TLS/SSL确保通信的三大安全性:加密(防止窃听)、身份验证(确保服务器的真实性)和数据完整性(防止数据被篡改)。
7. HTTPS的加密过程是怎么样的,怎么保证这个加密是真实有效的
HTTPS的加密过程:
- 客户端请求:客户端请求建立HTTPS连接,服务器发送数字证书。
- 验证证书:客户端验证服务器的数字证书是否可信(通过受信任的证书颁发机构签名)。
- 生成会话密钥:客户端生成一个随机的对称密钥,并用服务器的公钥加密后发送给服务器。
- 服务器解密:服务器用自己的私钥解密得到对称密钥。
- 加密通信:双方使用这个对称密钥进行加密的通信。
保证加密真实有效:
- 证书验证:客户端通过验证服务器的数字证书,确保其真实身份。
- 公钥加密:会话密钥通过服务器的公钥加密,只有对应的私钥能解密,确保密钥交换的安全性。
8.在后端开发过程中,你觉得服务器应该还关注一些什么方面,有没有了解
9.对SQL注入攻击怎么看
SQL注入攻击是通过向应用程序输入恶意SQL语句,利用应用程序对用户输入的处理漏洞,从而访问或操作数据库的攻击方式。
防范措施:
- 使用参数化查询:避免直接拼接用户输入到SQL语句中。
- 输入验证和转义:对用户输入进行严格检查和转义,防止恶意数据。
- 最小权限原则:确保数据库用户权限最低,限制能执行的操作。
10.数组和链表各自的应用场景有哪些
数组:固定大小的数据集合、快速随机访问、实现数据结构
链表:动态数据集合、实现栈和队列、内存管理
11.哈希表有没有了解,怎么解决哈希冲突
常用方法主要有两种:开放寻址法和链表法。
链表法:为每个哈希表中的桶(槽)维护一个链表。当多个元素映射到同一个桶时,它们被存储在该桶对应的链表中。通常使用std::list或std::forward_list来存储每个桶中的元素。
开放寻址法:当发生哈希冲突时,探测表中其他位置以寻找一个空槽或已删除的槽。方法包括线性探测、二次探测和双重哈希。
12.乐观锁和悲观锁
乐观锁:假设在事务处理期间不会发生冲突,因此在操作过程中不加锁,只有在提交时才检查是否发生了冲突。
实现方式:
- 版本号:每个数据项有一个版本号,每次更新数据时,都会检查版本号是否与读取时相同。如果相同,则执行更新操作并增加版本号;如果不同,则说明数据已被其他线程修改,更新失败,需要重新尝试。
- CAS:原子操作,先比较当前值与预期值是否相同,若相同则将新值写入;如果不相同,则表示数据已被其他线程修改,操作失败。
悲观锁:假设在事务处理期间会发生冲突,因此在操作过程中使用锁来保护数据,确保数据的独占访问。
实现方式:
- 互斥锁:使用互斥锁或其他同步机制来保护数据。在操作数据之前,先获得锁,操作完成后释放锁,确保其他线程在操作期间无法访问数据。
- 读写锁:在读取操作较多的情况下,使用读写锁可以提高性能。读操作获取共享锁,写操作获取独占锁。
13.遇到网络拥塞怎么办,详细讲一下(拥塞控制四种)
慢启动
原理:在连接开始时,TCP使用慢启动算法逐渐增加数据传输速率。开始时的拥塞窗口(cwnd)设为一个小值(通常为1个MSS),每当收到确认(ACK),拥塞窗口就会指数增加(每经过一个RTT,将cwnd增加一个MSS)。
拥塞避免
原理:当拥塞窗口达到慢启动阈值后,TCP转入拥塞避免阶段。在这个阶段,拥塞窗口以线性方式增加(每经过一个RTT,增加1个MSS),而不是以指数方式增加。如果发生拥塞(数据包丢失),则进入拥塞恢复阶段。
快速重传和快速恢复
快速重传:当发送方收到三个重复的ACK(即确认丢失的数据包的多个ACK)时,立即重传丢失的数据包,而不是等待超时。
快速恢复:在快速重传后,TCP会将ssthresh设置为拥塞窗口的一半,然后进入快速恢复阶段。快速恢复阶段类似于拥塞避免阶段,但不会进入慢启动。
主动队列管理
AQM机制通过在网络设备中主动管理队列长度,来预防拥塞的发生。
Random Early Detection (RED):当队列长度超过一定阈值时,随机丢弃或标记数据包,提前通知发送方网络负载较高。
Controlled Delay (CoDel):通过控制数据包排队延迟来防止队列积压,优化队列管理。
14.对MySQL 有什么了解吗
15.对称加密和非对称加密
特性 | 对称加密 | 非对称加密 |
---|---|---|
密钥数量 | 1(同一个密钥用于加密和解密) | 2(公钥和私钥) |
加密速度 | 较快 | 较慢 |
密钥管理 | 需要安全地分发和存储密钥 | 仅需保护私钥,公钥可以公开 |
密钥共享 | 需要在通信双方之间共享密钥 | 不需要在通信双方之间共享密钥 |
算法示例 | AES、DES、3DES | RSA、ECC、DSA |
安全性 | 依赖于密钥的安全性,密钥泄露会导致数据泄露 | 提供较强的安全性,密钥泄露仅影响私钥的保密性 |
应用场景 | 数据加密、文件加密、压缩文件加密 | 密钥交换、数字签名、证书验证 |
16.如何完成通信间的对称加密和非对称加密
流程:
- 生成公钥和私钥。
- 交换公钥。
- 用对方的公钥加密对称密钥。
- 用私钥解密对称密钥。
- 使用对称密钥加密和解密数据。
非对称加密用于密钥交换:
- 生成密钥对:每一方生成公钥和私钥。
- 交换公钥:通过安全或公开渠道交换公钥。
- 加密对称密钥:用对方的公钥加密生成的对称密钥。
- 解密对称密钥:用私钥解密对称密钥。
对称加密用于数据传输:
- 使用解密得到的对称密钥对数据进行加密和解密,进行实际的数据传输。
17.如何确保客户端收到的服务器发送的数据是真实有效的?
-
数据加密:
- 使用对称加密对数据进行加密,确保只有持有密钥的客户端能够解密和读取数据。
-
数字签名:
- 服务器对数据进行数字签名(使用非对称加密中的私钥),客户端用服务器的公钥验证签名的有效性,确保数据未被篡改,并验证数据的来源。
-
TLS/SSL:
- 使用TLS/SSL协议进行数据传输,这些协议提供加密、数据完整性检查和身份验证,确保数据的安全性和真实性。
算法题:最长连续序列
最长连续序列问题的简洁思路:
- 使用哈希集合:
- 将数组元素存入哈希集合中。
- 遍历数组中的每个元素,检查它是否是连续序列的起点。
- 从起点开始,连续检查集合中是否存在连续的下一个元素,并计算序列长度。
- 记录最长的连续序列长度。
时间复杂度:O(n),因为每个元素最多被处理两次(一次插入集合,一次查找)。
更多C++大厂面试题整理文档,C/C++后端开发学习资料、教学视频和 T9学习路线图,
↓↓↓↓↓↓见下面文章底部点击免费领取↓↓↓↓↓↓