操作系统和进程基础知识分享
并行和并发
并行:一个时刻里多个任务在执行
并发:一个时间段里多个任务在执行
什么是进程
进程:一个具有独立功能的程序在一个数据集合上的一次动态执行过程
进程的组成
- 程序的代码
- 程序处理的数据
- 程序计数器的值,指示下一条将运行的指令
- 一组通用的寄存器的当前值,堆,栈
- 一组系统资源(如打开的文件/网络资源/磁盘IO资源)
总之,进程包含了正在运行的一个程序的所有状态信息
进程与程序的联系
- 程序是产生线程的基础
- 程序每次运行构成不同的进程
- 进程是程序功能的体现
- 通过多次执行,一个程序可以对于多个进程,一个进程可以包括多个程序(调度程序)
进程和程序的区别
- 进程是动态的,程序是静态的;程序是有序代码的集合;进程是程序的执行,进程还有核心态/用户态
- 进程是暂时的,程序是永久的;进程是一个程序运行的状态过程;程序可以长久保持
- 进程和程序组成不同;进程包括了程序、数据、和进程控制块(即进程状态信息)
进程的特点
- 动态性:可动态创建、结束进程
- 并发性:进程可独立调度和占用处理机运行:并发并行
- 独立性:不同进程的工作不影响
- 制约性:因访问共享数据/资源或进程同步而产生制约
描述进程的数据结构:进程控制块(PCB)
操作系统为每一个进程都维护了一个PCB,用来保存与该进程有关的状态信息
- PCB是进程的唯一标记
- 进程的创建:为该进程生成一个PCB
- 进程的终止:回收它的PCB
- 进程的组织管理:通过对PCB的组织管理来实现
PCB含有的三大信息
- 进程标识信息:如本进程的标识,本进程的产生者标识(父进程标识),用户标识
- 处理机(CPU)状态信息保存区:保存进程的运行现场信息
· 用户可见的寄存器:用户程序可以使用的数据,地址寄存器
· 控制和状态寄存器:如程序计数器(PC),程序状态字(PSW)
· 栈指针:过程调用/系统调用/中断处理和返回时需要用到它 - 进程控制信息
· 调度和状态信息,用于操作系统调度进程并占用处理机使用
· 进程间的通信信息,为支持进程间的与通信相关的各种标识,信号,信件等,这些信息存在接收方的进程控制块中
· 存储管理信息,包含指向本进程映射存储空间的数据结构
· 进程所用资源,说明有进程打开,使用的系统资源,如打开的文件等
· 有关数据结构连接信息,进程可以连接到一个进程队列中,或连接到相关的其他进程的PCB
PCB的组织方式
链表:同一状态的进程其PID成一链表,多个状态对应多个不同链表(各状态的进程形成不同的链表:数据链表,阻塞链表)
索引表:同一状态的进程归入一个index表(由index指向PCB),多个状态对应不同的index表(各状态的进行形成不同的索引表:就绪索引表,阻塞索引表)
进程状态
- 进程生命周期管理
· 进程创建:引起进程创建的三个主要事件(系统初始化时、用户请求创建一个新进程、正在运行的进程执行了创建进程的系统调用)
· 进程运行:内核选择一个就绪的进程,让它占用处理机并执行
· 进程等待:在以下情况下,进程等待(就绪):请求并等待系统服务,无法马上完成;启动某种操作,无法马上完成;需要的数据还没有到。注:进程只能自己阻塞自己,因为只有进程本身才能知道何时需要等待某种事件的发生,当进程的时间片用完是进入就绪状态,而不是阻塞状态
· 进程唤醒 :唤醒进程的原因:被阻塞进行需要的资源可被满足;被阻塞的进程等待的事件到达;将该进程的PCB插入到就绪队列。注:进程只能被其他进程或操作系统唤醒
· 进程结束:进程结束的几种情况。正常退出(自愿的),错误退出(自愿的),致命错误(强制性的),被其他进程杀死(强制性的)
进程状态变化模型
进程的三种基本状态:
进程在生命结束前处于且仅处于三种基本状态之一不同系统设置的进程状态数目不同。
运行状态:当一个进程在处理机上运行时
就绪状态:一个进程获得了除处理机之外的一切资源,一旦得到处理机就可执行
等待状态(阻塞状态):一个进程等待某一事件而暂停运行时。如等待某资源、等待输入/输出完成
进程挂起
进程在挂起状态时,意味着进程没有占用内存空间,处于挂起状态的进程映射映射在磁盘上
- 阻塞挂起状态:进程在外存并等待某事件的出现
- 就绪挂起状态:进程在外存、但只要进入内存,即可运行
进程是如何切换
- 记录当前进程的状态保存到进程的PCB里面
- 把要运行的进程的PCB里面状态信息加载到CPU要运行的寄存器里面(切换上下文)
- 运行进程的断点送入处理器的程序指针PC
- 待运行进程就开始被处理器运行
为什么需要进程,他存在的意义
答:CPU的速度越来越快,能够带起的程序越来越多,进程的出现是对进行的程序封装,更有效的管理多个程序的独立运行。
状态队列
- 由操作系统来维护一组队列,用来表示系统当中所有进程的当前状态
- 不同状态分别用不同的队列来表示(就绪队列、各种类型的阻塞队列,分优先级)
- 每个进程的PCB都根据它的状态加入到相应的队列当中,当一个进程状态发送改变时,它的PCB从一个状态队列中脱离出来,加入到另外一个队列
什么是线程
进程当中的一条执行流程,线程=进程-共享资源
线程的优点和确定
优点:
-
一个进程可以存着多个线程
-
各个线程可以并发运行
-
各个线程之间可以共享地址空间和文件等资源
缺点:
-
一个线程崩溃,会导致其所属进程的所以线程崩溃
进程和线程对比
- 进程是对运行时程序的封装,是系统调度资源(内存、文件、网络等等)的分配的基本单位
- 线程是进程的子任务,cpu调度和分配的基本单位,实现进程内的并发
- 一个进程可以包含多个线程,线程依赖进程存在,并共享进程资源
- 线程能减少并发执行的时间和空间开销
· 线程的创建时间比进程短(不需要一些其他信息的管理,如内存的管理,打开的文件的管理,直接重用进程里面这些管理好的资源即可)
· 线程的结束时间比进程短(同理不需要考虑这些资源的释放的问题)
· 同一进程内的线程切换时间比进程短(同一个进程有同一个页表,在切换的时候不用再次去寻址转换,切换页表消耗比较大)
· 由于同一进程的各线程间共享内容和文件资源,可直接进行不通过内核的通信
用户线程和内核线程的对应关系
- 多对一,多个用户线程对应一个内核线程
- 一对一,一个用户线程对应一个内核线程
- 多对多,多个用户线程对应多个内核线程
用户线程的缺点
- 阻塞性的系统调用如何实现?如果一个线程发起系统调用而阻塞,则整个进程都在等待(对操作系统来说,它只能看到进程,所以会阻塞进程,进程内所有的线程都会阻塞)
- 当一个线程开始运行时,除非它主动的交出CPU的使用权,否则它所在的进程当中的其他线程将无法运行(操作系统可以,中断)
- 由于时间片分配给进程,故与其他进程相比,在多线程执行时,每个线程获得的时间片较少,执行会比较慢
内核线程(操作系统看得见的线程)
指在操作系统的内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理
- 在支持内核线程的操作系统中,由内核来维护进程和线程的上下文信息(PCB和TCB)
- 线程的创建、终止和切换都是通过系统调用/内核函数的方式进行,由内核完成,因此系统开销较大;
- 在一个进程当中,如果某个内核线程发起系统调用而被阻塞,并不会影响其他内核线程的运行
- 时间片分配给线程,多线程的进程可以获得更多的CPU时间
- Windows NT和Windows XP支持内核线程
轻量级进程
它是内核支持的用户线程,一个进程可有一个或者多个轻量级进程,每个量级进程由一个单独的内核线程支持,父进程是共享进程地址空间和系统资源。在Linux中,即是线程,也可以使进程。和普通的进程区别就是只有一个最小的执行上下文和调度程序所需的统计信息。
什么是线程安全
拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况
如何保证线程安全
- 互斥量(锁),通过互斥机制防止多个线程同时访问公共资源
- 信号量(Semphare),控制同一时刻多个线程访问同一个资源的线程数
- 事件(信号):通过通知的方式保持多个线程同步
进程间通信方式
- 管道/匿名管道/有名管道(pipe)
- 信号(Singal):比如用户使用ctrl+c产生SIGINT程序停止信号
- 消息队列(Message)
- 共享内存
- 信号量
- 套接字(socket):最常用的方式,web应用都是这种方式
死锁发生的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 占有并等待条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
解决死锁的方法
-
死锁预防
-
死锁避免
-
死锁检测
-
死锁恢复
死锁预防
只要发生死锁,上述四个条件一定满足,只要有一个条件不满足,就不会发生死锁
因此,要避免死锁,只要破坏上述四个条件之一。
破坏互斥:互斥性是使用资源是多进程能正确工作的前提,是必须保证满足的,不能破坏,否则就会出现问题如读写不一致
破坏占有并等待:保证当前进程请求所需要的资源,其他进程没有,当时会导致资源利用率低
破坏不可剥夺:如果进程占有某些资源,并且请求当前获取不到的资源,释放当前占有的资源,当之前释放的资源和要请求的资源能够获得的时候,进程再进行运行
破坏循环等待:对所有的资源进行排序,并要求每个进程按照资源的顺序去申请
死锁避免
在进程请求资源的时候,去判断是否会导致死锁,若可能出现死锁,则不分配资源。
银行家算法
死锁避免中著名的算法
前提条件:
- 多个序列
- 每个进程都必须能最大限度的利用资源
- 当一个进程请求一个资源,就不得不等待
- 当一个进程获得所有的资源必须在一段有限的时间释放他们
基于上述的描述,银行家算法通过尝试寻找每个进程获得最大资源并结束的进程请求的一个理想执行时序,来决定一个状态是否安全,不存在满足的执行时序的状态都是不安全的