- CPU加电
- 执行JMP指令跳转BIOS
- 执行BIOS
- 硬件自检
- 操作系统引导(加载主引导记录MBR(磁盘引导程序指示引导到哪个分区)->找活动分区即有操作系统的分区;活动分区加载分区引导记录PBR->启动管理器)
- 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
- 消息队列MessageQueue(消息传递):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
互斥
- 软件方法:由进程本身负责实施互斥,不需要操作系统支持。增加一定的开销
- 硬件方法:使用专门的机器指令来实现互斥。可减少开销,但依赖于硬件,难以成为通用的解决办法
- 操作系统层提供支解决互斥信号量机制、管程机制和消息传递机制
- 进程标识符信息
- 处理机状态信息
- 进程调度信息
- 进程控制信息
1、栈区 2、调度优先级 3、上下文数据
- 信号量实现让权等待,而Peterson(软件互斥)、swap、TestAndSet(硬件互斥)不满足
wait(S)P操作;signal(S)V操作 - 管程
- 名称、共享数据结构、对数据结构的操作、共享数据设置初值
- 条件变量:进入管程后的阻塞原因
- 信号量有值而条件变量无值
必要条件
- 资源互斥
- 资源不可被剥夺
- 进程保持资源并请求(不释放资源)-解决方法:一次申请所有所需资源
- 循环等待-解决方法:顺序资源分配法,只按照编号递增的顺序请求资源
- 死锁预防,申请资源时解决
- 死锁避免,银行家算法-系统安全状态
- 死锁检测和解除,资源分配图
- 分页作用及好处:
- 没有外部碎片
- 程序不必连续存放
- 易于扩展
- 分页原因:
有效地管理内存,提高内存利用率和保证进程的安全性(对于每个进程,操作系统会分配一个独立的页表来管理该进程的页面,不同的进程之间的内存空间被隔离开来)。 - 与分段的关系
- 分页是由于系统管理的需要。段则是信息的逻辑单位,分段的目的是为了能更好地满足用户的需要。
- 分页没有外部碎片,有内部碎片;分段有外部碎片没有内部碎片
两者都是离散分配方式、通过地址映射机构来实现地址变换
- 页面过小->页表太大,占用内存,增大地址转换开销,降低页面换入/换出的效率(缺页率高)
- 页面过大->页内碎片增多,降低内存的利用率(缺页率低)
cpu(运算器+控制器)、存储器、I/O
内存<-高速缓冲存储器(Cache)->CPU<-总线->外存
- 切换
用户调用操作系统服务(系统调用)或发生中断时,执行模式从用户模式切换到内核模式
当系统服务返回或中断返回到用户进程时,执行模式从内核模式切换到用户模式 - 为什么需要两种执行模式
保护操作系统和重要数据不受用户干扰 - 如何知道当前系统处于哪个执行模式下?
程序状态字(PSW) 中记录了当前系统所处的模式信息
- 什么时候发生进程切换
进程切换可以在操作系统从当前正在运行的进程中获得控制权的任何时刻发生。如中断、陷阱、系统调用等 - 进程切换,操作系统需要做什么
- 保存处理器的上下文环境,包括PC和其他寄存器
- 更新当前处于运行态的进程的进程控制块(PCB),如把进程状态改变为另一状态(就绪、阻塞、就绪/挂起或退出,具体哪种状态取决于发生进程切换的事件)
- 把上述进程的PCB移到相应的队列中(如就绪队列、事件i的阻塞队列等)
- 从就绪队列中选择另一个进程执行(进程调度)
- 更新所选择进程的进程控制块(PCB),如把进程状态变为运行态
- 更新内存管理的数据结构,如基地址寄存器和界限寄存器(分段机制)(易忘!)
- 恢复处理器在被选择进程最近一次切换出运行态的上下文:载⼊PC和其它寄存器最后一次保存的值
进程切换必然会存在模式切换(只有在内核模式下才能实现进程调度),但模式切换不一定会发生进程切换
子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。
fork()创建子进程时继承了父进程的数据段、代码段、栈段、堆,注意从父进程继承来的是虚拟地址空间,同时也复制了页表(没有复制物理块)。因此,此时父子进程拥有相同的虚拟地址,映射的物理内存也是一致的(独立的虚拟地址空间,共享父进程的物理内存)。
- fork()返回两次:父进程中返回一次,子进程中返回一次
- 父进程创建成功会返回子进程的PID,失败返回-1
- 子进程不会继续创建新的进程,fork()返回值是0;
- 多线程中某个线程调用 fork(),子进程会有和父进程相同数量的线程吗? 在Linux中,fork的时候只复制当前线程到子进程,其他进程“蒸发”
- 父进程被加锁的互斥锁fork后在子进程中是否已经加锁? 调用fork的时候,会复制父进程的所有锁到子进程中。 假设在fork之前,一个线程对某个锁进行的lock操作,即持有了该锁,然后另外一个线程调用了fork创建子进程。可是在子进程中持有那个锁的线程却"消失"了,从子进程的角度来看,这个锁被“永久”的上锁了,因为它的持有者“蒸发”了。
- 写时拷贝 内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。
- 原来的进程和fork()出来的子进程可以同时、自由的读取内存。
- 子进程(父进程)对内存进行修改的话,那么这个内存就会复制一份给该进程单独使用,以免影响到共享这个内存空间的其他进程使用。
- 僵尸进程 父进程提前比子进程先结束了,子进程现在处在悬空的状态,子进程一直还在,尽管它已经运行结束,这是因为它的第一任父进程已经结束了,现在它被托付给0号内核进程,0号进程是永远不会结束的。
- fork()系统调用被用于创建一个新进程。
- exec()系统调用被用于在进程中启动新程序。
- fork()创建了一个新的进程来并行执行不同的代码
- exec()在当前进程中替换代码和数据来运行一个新程序。
- 易于调度
- 提高并发性。通过线程可以方便有效地实现并发
- 开销小。创建线程比创建进程要快,所需的开销也更小
- 有利于发挥多处理器的功能。通过创建多线程,每个线程都在一个处理器上运行,从而实现应用程序的并行,使每个处理器都得到充分运行。
进程是资源分配的基本单位,线程是调度的基本单位
- 从属关系:一个线程必定属于也只能属于一个进程;而一个进程可以拥有多个线程并且至少拥有一个线程。
- 资源:属于一个进程的所有线程共享该线程的所有资源,包括打开的文件、创建的Socket等。不同的进程互相独立。
- 切换代价:线程又被称为轻量级进程。进程有进程控制块,线程也有线程控制块。但线程控制块比进程控制块小得多。线程间切换代价小,进程间切换代价
- 执行过程:进程是程序的一次执行,线程可以理解为程序中一段程序片段的执行
- 内存空间:每个进程都有独立的内存空间,而线程共享其所属进程的内存空间。
用辅助存储器(一般指磁盘)作为内存的补充。运行进程时只把最近一段时间内要访问的页/段装入内存,其余页/段放在外存,需要时再利用请求调入页/段功能和置换功能将其调入内存
- 大小:实际容量 <= 内存容量+外存容量;最大容量 <= 地址位数能容纳的最大容量(超过的部分没有意义,访问不到)
- 利用率:虚拟内存可提高系统资源利用率,方便用户编程:
每个进程只需装入(最近一段时间内访问的)部分页/段,所以内存中可放置更多进程,系统并发度更高,于是提高了CPU利用率(多道程序度)更高,于是提高了CPU利用率和内存利用率 - 速度成本:从逻辑上扩充容量;访问速度接近于内存,每位(bit)成本接近于外存
- CPU通过生成一个虛拟地址访问主存
- 虚拟地址转换为物理地址的任务叫做地址翻译
- 关中断
- 保存断点
- 中断服务程序寻址
以上为中断隐指令(cpu完成)
- 保存现场
- 开中断
- 执行中断服务程序
- 关中断
- 恢复现场
- 开中断,中断返回