前言
你好,我是小莱,最近秋招已经开始了,有的人一边实习一边交实验报告一边准备秋招,如此高强度下面试结果往往不如人意,但关键还是要稳住心态,做好每一次面试的复盘,查漏补缺。我整理了最近的面试经历,这次精选的面试题以计算机基础知识为主,算法题比较简单。
知识点
1. 进程通信的方式有哪些,平时用过吗?
-
管道(Pipes):
-
概念:管道是一种半双工的通信方式,它允许一个进程将数据传递给另一个进程。管道有两种类型:匿名管道和命名管道。匿名管道只能用于父子进程之间的通信,命名管道可以用于任何两个进程之间。与匿名管道不同,命名管道在文件系统中被创建为一个特殊的文件,它的生命周期不依赖于进程,可以随时被不同的进程用于读写数据。
-
实际应用:在类Unix系统中的管道符
|
就是使用匿名管道的例子。下面这行命令将 ps 生成的详细进程信息传递给 grep,输出与 processname 相关的信息条目。
ps -ef|grep processname
-
-
信号(Signals):
-
概念:信号是一种用于通知进程发生某个事件的机制。信号是一种异步的、较为简单的通信方式,用于传递控制信息,如中断、终止等。
-
实际应用:在Linux系统中,
kill -l
命令可以查看所有信号。当我们用 Ctrl C 终止一个进程的时候,就是通过操作系统内核传递一个信号给目标进程,进程根据其信号处理函数终止了自己。
-
-
信号量(Semaphores):
-
概念:信号量是一种用于控制对共享资源访问的同步机制。信号量通常用于进程间的互斥和协调,防止资源竞争和死锁。
-
实际应用:在多进程编程中,信号量可以用于实现互斥锁。例如,生产者-消费者问题中,可以使用信号量来控制缓冲区的访问,确保生产者和消费者不会同时访问缓冲区。
-
-
消息队列(Message Queues):
-
概念:消息队列是一种先进先出(FIFO)的数据结构,允许进程之间通过队列传递消息。消息队列可以实现异步通信,允许进程将消息放入队列中,接收方可以在稍后时间读取消息。更适合需要异步、复杂消息处理和任务调度的场景。
-
实际应用:在一个分布式系统中,应用程序可以使用消息队列(如RabbitMQ、Kafka)来实现不同服务之间的异步通信和任务调度。
-
-
共享内存(Shared Memory):
-
概念:共享内存允许多个进程访问同一块内存区域,以便快速地交换数据。共享内存是最快的IPC机制,但需要适当的同步机制以避免数据竞争。
-
实际应用:在数据处理应用中,例如大规模数据分析,多个进程可以使用共享内存区域来存储中间结果,以加速数据处理过程。
-
-
套接字(Sockets):
-
概念:套接字是一种网络通信机制,用于在不同主机或同一主机上的不同进程之间传输数据。Socket 可以选择不同的网络协议(如TCP、UDP)进行通信。
-
实际应用:在网络应用中,Web服务器(如Apache)通过 Socket 与客户端(如浏览器)进行通信。访问一个网站时,浏览器与服务器之间的数据传输通常是通过 Socket 实现的。
-
2. 线程在用户态和内核态之间有哪些映射方式,有什么区别?
1. 一对一模型(1:1)
一个用户级线程直接映射到一个内核级线程。
- 最大线程数量受到内核数量的限制;
- 大部分操作都会映射到内核线程上,引起用户态和内核态的频繁切换,增加开销。
2. 多对一模型(N:1)
多个用户级线程映射到一个内核级线程。
- 很多操作在用户态就可以完成,减少了内核上下文切换的开销,有点像协程;
- 线程数量不受限制;
- 一个线程的阻塞会影响到所有线程。
3. 多对多模型(N:M)
多个用户级线程动态映射到多个内核级线程。
- 代码写了多线程实际可能并发也可能并行,两边都在调度,增加复杂性和不确定性,操作系统内核一般不用这个。
- 理论上可以最大限度地利用多核处理器的并行计算能力。
3. 死锁的产生原因,有什么好的解决方式?
原因
多个线程或进程循环等待对方持有的资源导致都无法正常运行。
解决方式
-
预防死锁
-
破坏互斥条件:允许资源被多个进程共享。
-
破坏占有和等待条件:要求进程在请求任何资源之前,释放所有已经占有的资源。
-
破坏不可抢占条件:允许资源被抢占。
-
破坏循环等待条件:通过资源排序算法,确保每个进程按顺序请求资源。
-
-
避免死锁
-
银行家算法:记录系统资源和进程状态,包括资源总量、进程的最大需求、已分配资源等,当进程请求资源时,先进行安全性检查,即当前空闲资源能否满足其要求,如果够让它运行才分配。
-
4. 单例模式的实现方式,需要考虑哪些细节?
-
私有构造函数:为了防止外部通过
new
关键字创建类的实例,单例类的构造函数应该是私有的,并且要禁止拷贝构造函数和赋值操作符。 -
静态实例变量:单例类需要用静态变量来持有唯一的实例,静态变量需要在类外初始化否则编译报错。
-
公有访问方法:提供一个公有的静态方法,如
getInstance()
,用于获取唯一的实例。这个方法需要检查实例是否已经创建,如果没有,则创建它;如果已经创建,则返回该实例。 -
线程安全:在多线程环境中,需要确保单例的实例化过程、静态变量的写过程是线程安全的。可以通过同步机制来实现,但这可能会影响性能。有多种方法可以确保线程安全,如使用同步锁、双重检查锁定模式(回头拎出来多线程部分单独讲)等。
-
延迟初始化:就是懒汉模式,不用的时候可以节省资源。
代码示例:
#include <iostream>
#include <mutex>
class Singleton {
private:
// 私有静态指针变量,指向类的唯一实例
static Singleton* instance;
// 用于同步的互斥锁
static std::mutex mutex;
// 私有构造函数,防止外部直接创建实例
Singleton() {
// 初始化代码...
}
// 禁止拷贝构造函数和赋值操作符,防止复制实例
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
// 公有静态方法,提供全局访问点
static Singleton* getInstance() {
// 双重检查锁定模式(Double-Check Locking)
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
// 示例方法
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
int main() {
// 获取单例对象并调用其方法
Singleton* singleton = Singleton::getInstance();
singleton->doSomething();
return 0;
}
5. http 和 https 有什么区别?
-
HTTPS在HTTP的基础上加入了SSL/TLS协议,提供了数据加密、完整性校验和身份验证。
-
协议过程简述:客户端请求证书,服务器返回证书,客户端使用证书中的公钥加密一个随机数发给服务端,服务端用私钥解密得到随机数,双方基于随机数派生一个会话密钥进行加密通讯。
6. 手撕算法:删除倒数第n个链表节点。
- 遍历一遍确定链表长度,再定位去删节点,虚拟头结点处理边界情况。
" Simplicity is the soul of efficiency. "
The End