os 1- 内核、系统调用、进程和线程
ddatsh
os很多思想、经典算法都可在日常开发各种工具或框架中找到它们的影子
学好OS提高思考深度及对技术理解力
内核
硬件与软件之间的一个中间层,将硬件资源抽象到一个更高的层次上,帮助上层应用高效地使用资源
当若干个程序并发地运行时,内核扮演着一个资源管理器的角色,将共享资源(CPU 时间,磁盘,网络等)分配到各个进程
Linux:
单内核结构,同时吸收微内核的优点:模块化设计,支持动态装载内核模块
还避免了微内核设计上的缺陷,让一切都运行在内核态,直接调用函数,无需消息传递
系统调用
user、kernel mode
系统调用大致分类:
- 设备
- 定时
- 文件
- 进程控制
- 进程通信
- 内存
- 用户,命名空间
进程和线程
层级管理
两个系统调用配合,创建出一个新的进程
-
fork:
Linux 用COW
-
exec:
将一个新的程序加载到当前进程的内存中执行,旧程序的内存页会被刷出,其内容将替换为新的数据,然后开始执行新的程序
线程
程序会需要多个代码执行流,多个进程来处理这个又需要通信机制来交换数据
用线程来解决就不需要这部分通讯工作,所有线程共享该进程的数据和资源,只需同步机制对资源进行互斥的访问即可
Linux 通过 clone 方法创建线程,工作方式类似于 fork,确认哪些资源与父进程共享,哪些资源为线程独立创建
命名空间
使不同的进程可以看到不同的系统视图,以前的全局资源现在具有了不同的分组,如,每个命名空间内只能看到同组内的 PID 集合
进程状态
进程间通信方式
-
匿名管道(Pipes) :
有亲缘关系
的父子或兄弟进程间通信 -
有名管道(Names Pipes) :
可无亲缘关系通信,遵循 FIFO,以磁盘文件方式存在
-
Signal :
通知接收进程某个事件已经发生
-
消息队列(Message Queuing) :
可随机查询,不一定要FIFO读取,可按消息类型读取。克服信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺陷
-
Semaphores :
计数器,用于多进程对共享数据的访问,意图在于进程间同步,解决同步相关问题并避免竞争条件
-
共享内存(Shared memory) :
多个进程可访问同一块内存空间,及时看数据更新。要依同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式
-
Sockets :
可看做不同主机间的进程进行双向通信的端点
线程间同步的方式
-
Mutex:
拥有互斥对象的线程才有访问公共资源的权限。因为
互斥对象只有一个
,所以可以保证公共资源不会被多个线程同时访问Java 中 synchronized 和各种 Lock 都是这种机制
-
信号量(Semphares) :
允许同一时刻多个线程访问同一资源,但需要控制同一时刻访问此资源的最大线程数量
-
事件(Event) :
Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作
进程调度算法
-
先到先服务(FCFS) :
从就绪队列中选最先进入的进程为之分配资源,立即执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度
-
短作业优先(SJF) :
从就绪队列选出估计运行时间最短的
-
时间片轮转 :
古老,简单,公平且使用广,又称 RR(Round robin)调度。每个进程被分配一个时间片,即该进程允许运行的时间
-
多级反馈队列 :
SJF,仅照顾短进程而忽略了长进程 。多级反馈队列既能使高优先级作业得到响应又能使短作业(进程)迅速完成
-
优先级调度 :
为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级
地址空间和特权空间
内存通过指针寻址,CPU 字长决定了所能管理的内存地址空间最大尺寸,32 位系统4GB,64 位系统是 2^64 B
地址空间的最大长度和实际可用的物理内存大小无关,因此称之为虚拟地址空间
从进程的角度来看,地址空间中只有自身这一个进程,无法感知到其他进程的存在
Linux 将虚拟地址空间划分为两个部分,内核空间和用户空间
用完整的 64 位字长描述地址空间,所能描述的虚拟地址空间是巨大,用不了这么大的空间,一般用较短的位数来描述地址空间,比如 42 或者 47 位
CPU 提供了几种特权级别,进程可以驻留在某一特权级别。每个特权级别都有各种限制,例如对执行某些汇编语言指令或访问虚拟地址空间某一特定部分的限制