虚拟内存
操作系统会提供一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起来。
如果程序要访问虚拟地址的时候,由操作系统转换成不同的物理地址,这样不同的进程运行的时候,写入的是不同的物理地址,这样就不会冲突了。
多级页表为什么可以省空间? - 知乎 (zhihu.com)
访问的页在内存中不存在 需要从磁盘上去调入 这个时候就会产生中断 这个中断是由于缺页导致 所以叫缺页中断 cpu会响应中断 cpu会保存当前的环境 然后从磁盘上找到对应的页加载到内存 恢复当前cpu的环境
简述一下操作系统中的缺页中断_是否会发生缺页中断。如果会则简述中断处理过程-CSDN博客
fork
【Linux】fork()函数详解 (深入浅出 实例讲解)_fork函数-CSDN博客
fork函数调用一次返回两次
在父进程中返回的是子进程的pid
在子进程中返回的是0
小于0就是出错了
创建进程成功会出现两个进程。一个是父进程 一个是子进程
怒啃 24 小时,终于搞懂上下文切换! - 陈树义 - 博客园 (cnblogs.com)
一文让你明白CPU上下文切换 - 知乎 (zhihu.com)
消息队列
管道的通信方式是效率低的,因此管道不适合进程间频繁地交换数据。
对于这个问题,消息队列的通信模式就可以解决。比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。
一文搞懂六大进程通信机制原理(全网最详细) - 知乎 (zhihu.com)
锁
死锁
互斥条件:当资源被一个线程使用时,别的线程不能使用
不可剥夺条件:当线程已经持有了资源 ,在自己使用完之前不能被其他线程获取
持有并等待条件:线程 A 在等待资源 2 的同时并不会释放自己已经持有的资源 1。
环路等待条件:线程1等待线程2占有的资源,而线程2等待线程1占有的资源形成一个环路
死锁只有这四个条件都发生时才有可能出现,也就是我们只要破坏其中的一个就可以预防死锁的发生。
但是不适用
破坏占有且等待:每个请求者一次性申请所有需要的资源,如果无法一次性申请所有的资源,那就进行等待
破坏不可剥夺条件:当某个线程拿到部分资源之后,又去申请另一个资源,如果申请不到,就会主动释放他占有的所有资源
破坏环路等待:给每个资源标上序号,先申请资源序号小的再申请序号资源大的,这样线性化申请资源
2.4.2 死锁的处理策略-预防死锁(破坏互斥条件、破坏不可剥夺条件、破坏请求和保持条件、破坏循环等待条件)_剥夺资源法是预防死锁吗-CSDN博客
死锁的产生、防止、避免、检测和解除 - 知乎 (zhihu.com)
银行家算法就是当进程请求一组资源时,先判断这个进程在请求了指定的资源后能不能处于安全状态,如果可以,就同意这个请求,如果不行,则阻塞该进程直到能够满足。
连前端都看得懂的《Nginx 入门指南》 - 掘金 (juejin.cn)
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1, mtx2;
void func1() {
// 锁定 mtx1
mtx1.lock();
std::cout << "线程1锁定了互斥量1" << std::endl;
// 暂停一下,确保 func2 开始执行并且锁定了 mtx2
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// 尝试锁定 mtx2
mtx2.lock();
std::cout << "线程1锁定了互斥量2" << std::endl;
// 解锁
mtx1.unlock();
mtx2.unlock();
}
void func2() {
// 锁定 mtx2
mtx2.lock();
std::cout << "线程2锁定了互斥量2" << std::endl;
// 暂停一下,确保 func1 开始执行并且锁定了 mtx1
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// 尝试锁定 mtx1
mtx1.lock();
std::cout << "线程2锁定了互斥量1" << std::endl;
// 解锁
mtx2.unlock();
mtx1.unlock();
}
int main() {
std::thread t1(func1);
std::thread t2(func2);
t1.join();
t2.join();
return 0;
}