目录
Linux介绍
程序演变
- 单道程序:一次运行一个程序
- 多道程序:OS控制程序切换,'同时'运行多个程序,基于时间片切换进程
- 资源利用:IO等待时,可以让其他程序执行
- 公平:多用户、多程序基于时间片交替执行
- 便捷:多进程一个完成一种任务通过交互,而不是一个程序完成全部任务
- 多线程:多CPU场景下,一个进程只能占用一个CPU会浪费
- 简化建模:更贴近人日常行为,等待水开时读报
- 简化请求处理
多核 和 多CPU的区别
- 多核是一个CPU里有多个计算引擎,可以让多线程并行工作;
- 多CPU是多个CPU,可以多进程并行工作
- CPU内含Cache和MMU(分页内存管理单元,处理虚存映射的)
- 所以多CPU有多个地址空间,可以让多进程并行
设计哲学
- 一切皆文件;
- 单一职责,每个程序只做好一件事,复杂的功能通过程序间协作实现;
- 内核态、用户态,通过系统调用提高超过用户权限的功能;
- 使用小写字母并尽量短
用户态和内核态
- 出于资源分配、安全考虑,CPU有特权级别(0,1,2,3),不同级别能访问不同资源,Linux只用了0和3,就是内核态、用户态
- 地址空间可以分为内核空间和用户空间,用户代码无权访问内核空间、底层硬件,需要访问时,通过系统调用切换到内核态时,CPU进入0级特权,使用内核栈执行内核代码来完成
常见系统调用
- 进程控制、文件系统、系统控制、内存管理、网络管理、socket管理、用户管理、进程间通信
中断
- 作用:允许暂停当前任务,转而去执行更紧急的任务
- 流程:
- 收到中断源发出的中断请求
- 保护现场(现在执行的程序的执行上下文)
- 调用对应的中断处理程序进行处理
- 关中断,恢复现场
- 中断返回
Ext2第二扩展文件系统
- 为文件预分配磁盘块,使得文件拓展时避免了磁盘碎片
- 对磁盘块分组,将同组磁盘块放到相邻磁道内,减少平均寻道时间,局部性原理
- 支持只读、只追加文件
注:磁盘类似一个多个光盘插到一个转轴上,磁道就是每一个光盘,每个磁道分扇区
进程
进程状态:新建->就绪(除了CPU其他资源都齐全了)->运行->等待(等待所需资源释放)->终止(可以被释放了)
进程间通信
运行在同一OS中的不同进程间的消息传递,有些通信需要同步处理
- 管道:父进程打开一个管道文件,fork后子进程同样能访问同一个管道文件描述符( 父进程关闭读,子进程关闭写,就形成了一条单向通信数据流)
- FIFO(具名管道):有一个路径名与之关联,因此允许无亲缘关系的进程访问同一个FIFO
- 消息队列
- 共享内存:将同一块物理内存映射到通信双方的地址空间(效率最高,需要加锁)
- 同步(互斥量、条件变量、读写锁、文件和记录锁、信号量)
- socket:双方或多方约定一个端口,用一个监听socket绑定它,然后通信
管道与消息队列的区别
- 管道最后一次关闭时,数据会被丢弃,而消息队列具有随内核的持续性
- 管道传输字节流(没有边界,也没有类型信息),消息队列存的是有格式的消息
- 管道传输时接收方必须也在场
僵尸进程和孤儿进程
fork的过程:创建一个新进程,与父进程执行相同的代码,拷贝父进程的资源,子进程从fork函数开始执行,子进程fork返回结果为0,父进程fork返回子进程ID,以此做区分,让它们做不同的事
僵尸进程:子进程运行完毕后,父进程没有wait回收其资源
产生原因:Linux提供了一种机制,保证父进程可以取得子进程退出时的状态信息,子进程退出时,内核释放其大部分资源,但保留进程ID、运行时间、退出状态,等待父进程wait(阻塞)来取后才释放
解决方法:杀死父进程,僵尸进程变成孤儿进程,被init进程领养负责回收
孤儿进程:父进程运行完毕,子进程变成孤儿进程
预防措施:
- 父进程wait阻塞等待子进程完毕后释放资源
- fork子进程,子进程fork孙进程执行任务,子进程退出,孙进程被Init接管
- 父进程不在乎子进程结束状态,通过signal通知内核随便处理,内核负责释放资源
- 父进程通过signal注册handler,等子进程结束后父进程收到信号,在handler里调用wait回收
学习自百度百科 僵尸进程词条 https://baike.baidu.com/item/%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B/1036577?fr=aladdin
守护进程:没有控制终端与用户交互,父进程是init进程
为什么浏览器用多进程架构?
- 端口
- 更强的健壮性:多线程共享地址空间,容易一个线程的崩溃导致整个应用的崩溃
- 隔离,更安全:某一个页面出了病毒后不容易危害到其他页面
死锁
- 四个必要条件:资源互斥、非剥夺、请求保持、循环等待
- 避免--银行家算法,安全路径
进程调度算法
短作业优先 先来先服务 高响应比优先 时间片轮转 多级反馈队列 响应比 = (等待时间+运行时间)/ 运行时间 多个优先级队列,所分配的时间片逐渐增加
进程先到1级,时间片结束后到2级,...
短作业优先+先来先服务 评估指标:
- 吞吐量:单位时间完成的任务数
- 周转时间:等待时间+运行时间,提交任务到执行完任务的时间
- 平均周转时间:每个进程的平均周转时间
- 带权周转时间:周转/运行,如果有些任务长时间等待,影响更大
- 带权平均周转时间
线程
多线程 对于提高并发性的意义:
- 充分利用多核CPU的特性;
- 在IO操作繁忙时让出CPU资源
线程间通信:
- 互斥量:实现对共享资源的互斥访问,加锁
- 信号量:PV操作,实现同步
- 信号量SV(可以认为是可获得的资源数目)
- P操作:获取资源
- if SV>0:SV-1
- else 挂起当前线程
- V操作:释放资源
- if SV>0:SV+1
- else 唤醒一个挂起线程
- 条件变量:线程间的通知机制
- 当条件变量达到某个值时,唤醒等待这个条件变量的线程(1或多)
进程、线程、协程的区别
关系:多线程共享进程的系统资源,一个线程含多个协程
进程 线程 协程 定义 进行中的程序 轻量级进程,与其他进程共享了系统资源的进程 一个协程是一个函数以及保存函数运行时数据的栈
运行上下文 系统资源:打开的文件表、页表、页目录等
硬件上下文:CPU寄存器(存于tss段)、栈中数据
CPU寄存器、栈(存储执行期间的临时变量) CPU寄存器、栈 切换时的消耗 切换页目录和页表,使用新的虚拟地址空间;
缓存、快表失效;
切换 CPU寄存器、用户栈;
用户态-内核态转变
切换 CPU寄存器、栈
线程调度由内核进行,也涉及内核态转换
切换 CPU寄存器、栈;
用户级的轻量线程,由用户自行调度,内核对此一无所知
最小系统资源分配单位 最小调度单位
虚存管理
虚拟内存的好处
- 安全性:
- 读写内存的安全性,由于物理内存是随意访问的,通过CPU特权级别和MMU(内存管理单元)的内存保护机制,使虚页在不同特权下有不同访问权限,这样可以保护只读段、内核空间
- 进程间的地址隔离,防止误操作别的进程的数据
- 效率:
- 通过映射可将离散的内存块利用起来,避免有足够空闲空间却无法分配的问题
- 支持多进程运行,分配的虚拟空间可能远大于实际物理空间,进程的虚页可能映射到内存、硬盘中
- 虚拟内存地址:多级页表号+页内偏移量,通过查询页表找到内存中对应的页,若查不到则缺页,调页
- 多级页表好处:时间换空间,通过分级,共享一些高级的位,节约内存,可以实现将页表的部分加载到内存
- 快表:缓存了部分页表查询结果
学习自 https://blog.csdn.net/u012150590/article/details/51352019
页面置换算法
LRU LFU FIFO 最近最少使用 最少使用频率 淘汰最早加载到内存的
内存寻址
- 地址分类:
- 逻辑地址:机器指令中的地址
- 虚拟地址:开启分页时的逻辑地址
- 线性地址:段页式下的逻辑地址
- 物理地址:实际内存地址
- 段页式虚存管理:程序分段,段分页,逻辑地址由 段号-段内页号-页内地址组成
- 寻址时,去段表寄存器(存段号--段起始地址)根据段号查段的起始地址
- 然后根据页号计算出页的起始地址(页是定长)
- 再去页表里查页映射的物理块的起始地址
- 然后用页内偏移+物理块起始地址就是访问地址了
- 所以要3次访问内存:段表、页表、物理内存
学习自 百度百科
socket API
- 概述:socket API是Linux内核提供的网络层、传输层、数据链路层协议实现的调用接口
- 作用:
- 负责用户空间和TCP/UDP收发缓存区之间数据复制
- 修改内核各层协议的头部或其他数据结构,精细控制底层通信,如setsockopt设置IP报生存时间
- socket通信过程:
- 服务端:
- 建立socket
- 创建socket addr(ip,端口)
- bind绑定(命令socket):将socket与socket地址绑定
- listen:创建监听队列来存放待处理的客户连接
- accept:阻塞等待连接建立,返回与客户端连接的socket
- read, write:通信
- 客户端:
- 建立socket(匿名)
- connect:发起连接
- close:关闭
listen函数中的backlog是什么意思?设置的意义?
- 内核会为listen socket维护两个队列
- 未完成连接的队列:收到SYN发回ACK后的socket,SYN_RECV状态
- 完成连接的队列:收到ACK完成连接建立
- 两个队列长度之和>backlog 时,新连接请求会被拒绝
- 意义:控制处理连接请求的速率
一些问题
- 为什么进程进行上下文切换时的开销比线程进行上下文开销大?
- 页表切换、快表失效
- 线程共享进程的什么资源?
- 系统资源:文件描述符、地址空间、网络连接
- 进程和线程使用上的区别?
- 程序执行需要资源,多进程更安全
- 多核时多线程优于多进程?
- 理由1:多线程能利用多核进行并行计算
- 理由2:多线程共享地址空间,能减少地址切换的开销
- 进程和线程的区别,为什么进程的创建销毁比线程开销大?
- 进程是系统资源分配、竞争的最小单位,线程是CPU调度的最小单位
- 可以认为进程包含多个线程,多线程共享进程的系统资源,如文件描述符、地址空间
- 线程有独立的栈空间(存储执行期间的临时变量)、一组寄存器值
- 进程创建时要分配系统资源,销毁时回收资源,如文件描述符、PCB、页表
- 虚拟内存最大可以到多少?能超过物理内存(比如说4G)的大小吗?能到1TB吗?
- 32位地址线的话最大是2^32=4G,可以超过物理内存,可以,但是没有意义,因为你的程序也只能访问到2^32个地址单元
- malloc函数,操作系统是怎么分配内存的?
- 库会先申请一大块作为内存池,避免频繁系统调用,将它们分成8、16、24、...、256的块,
- 小内存直接从里面取一块,大的才再申请
- cache的缓存如何和外存的缓存保持一致性?
- 写直达:同时向缓存、内存里写
- 写回:先写到缓存里,当缓存块要被替换时才写回内存
- 多核时缓存一致性 -- 写传播:写缓存时通过总线广播给其他CPU
- 共享内存注意的点
- SHMMAX总体的大小限制
- 创建共享内存时的key要唯一,key设置为IPC_PRIVATE,由OS保证唯一性,操作系统忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID