进程与线程
-
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态的概念,竞争计算机系统资源的基本单位。
系统进行资源分配和调度的一个独立单位。
-
线程:是进程的一部分,一个没有线程的进程可以被看作是单线程的,线程有时候又被称为轻权进程或轻量级进程,也是CPU调度的一个基本单位。
进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。
注意这里描述的进程线程概念和实际代码中所说的进程线程是有区别的。编程语言中的定义方式仅仅是语言的实现方式,是对进程线程概念的物化。
两者的关系
- 一个线程只能属于一个进程,一个进程可以有多个线程,但至少有一个线程。线程时操作系统可识别的最小的执行和调度单位。
- 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
- 处理机分给线程,即真正在处理机上运行的是线程。
- 线程在执行的过程中,需要协作同步。不同进程的线程间要利用消息通信的方法实现同步。
两者的区别
- 进程拥有自己独立地址空间,线程没有
- 进程是资源分配的最小单位,线程时cpu调度的最小单位
- 进程和线程通信方式不同
- 进程上下文切换开销大,线程开销小
- 一个进程挂掉了不会影响其他进程,而线程挂掉了会影响其他线程
工厂与员工:
公司与员工:
火车和车厢:
进程的状态,各个状态之间的转换
- 就绪:进程已处于准备好运行的状态,即进程已分配到除CPU外的所有必要资源后,只要再获得CPU,便可立即执行。
- 执行:进程已经获得CPU,程序正在执行状态。
- 阻塞:正在执行的进程由于发生某事件,暂时无法继续执行的状态。
孤儿进程和僵尸进程
进程间通信方式
进程通信,是指进程之间的信息交换。操作系统隐藏了进程通信的实现细节,进程通信对于用户是透明的。
对于用信号量进行的进程间的互斥和同步,由于其所交换的信息量少而被归结为低级通信。
高级进程通信指的是用户可以利用操作系统所提供的一组通信命令传送大量的数据的一种通信方式。可分为三大类:共享存储器系统、消息传递系统、管道通信系统。
- 管道:管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。
- 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
- 消息队列:是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现的。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 共享内存:共享内存允许两个或多个进程访问同一个逻辑内存。这一段内存可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。共享内存是最快的IPC方式,它是针对其它进程间通信方式运行效率低而专门设计的。
- 套接字:套接字也是一种进程间通信机制,与其它通信机制不同的是,它可用于不同机器间的进程通信。
线程的哪些资源共享,哪些不共享
- 共享资源有:
- 堆
- 全局变量
- 静态变量
- 文件等公用资源
- 独享资源有:
- 栈
- 寄存器
线程安全
线程安全指的是多线程的程序的运行结果是可预期的,而且与单线程的程序运行结果一样。
进程同步和互斥
当有多个线程的时候,经常需要去同步这些线程访问同一个数据或资源。
进程同步的主要任务:对多个相关进程在执行次序上进行协调,以使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。
同步机制遵循的原则:
- 空闲让进
- 忙则等待(保证对临界区的互斥访问)
- 有限等待(有限等待时间,避免死锁)
- 让权等待(当进程不能进入自己的临界区时,应该释放处理机,以免陷入忙等状态)
临界资源和临界区
对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源(例如打印机)。对于临界资源的访问,必须是互斥进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区。
死锁
概念
多个进程在运行的过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
产生原因:竞争资源和进程间推进顺序非法。
产生的必要条件
- 互斥条件
- 请求与保持条件
- 不剥夺条件
- 循环等待条件
有一个条件不成立,则不会产生死锁。
解决的基本方法
- 预防死锁
- 避免死锁
- 检测死锁
- 解除死锁
进程调度
调度种类
-
高级调度:又称作业调度,它决定把后备作业调入内存运行。
-
低级调度:又称进程调度,它使就绪队列的某进程获得cpu。
-
中级调度:又称为在虚拟存储器中引入,在内、外存兑换区进行进程对换。
非抢占式调度和抢占式调度
-
非抢占式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度某事件而阻塞时,才把处理机分配给另一个进程。
非抢占式调度的实际是:
- 线程阻塞
- 线程时间片执行完毕
- 线程任务执行完毕
-
抢占式:操作系统将正在运行的进程强行暂停,由调度程序将cpu分配给其他就绪进程的调度方式。
线程分为普通线程和核心线程。
- 普通线程的可以访问的资源比较少,可以被其他线程所抢占
- 核心线程可以抢占普通线程,而核心线程不能够被其他线程抢占,只能被中断。
什么是中断?
中断是对正在占用CPU执行权线程进行保存执行环境和变量,然后将其放置到就绪队列中,由中断处理程序进行处理。
中断分为软中断和硬中断
- 软中断可以理解为软件中断,是指 CPU设置的程序在特定情况下进行中断操作
- 硬中断:是指硬件造成的中断,比如说键盘输入等等硬件所造成的中断。
调度算法
- FCFS先来先服务
- 调度顺序就是人物到达就绪队列的顺序
- 公平、简单、非抢占、不适合交互式
- 未考虑任务特性,平均等待时间可以缩短
- SJF最短作业优先
- 可以保证最小的平均等待时间
- SRJF可抢占式的最短作业优先
- 比SJF更有优势
- 优先权
- 每个任务关联一个优先权,调度优先权最高的任务
- 优先权太低的任务一直就绪,得不到运行,出现“饥饿”现象
- RR时间片轮转
- 定时有响应,等待时间短
- 上下文切换次数较多
- 时间片太大,响应时间太长,吞吐量变小,周转时间长;时间片过长,退化为FCFS
- 多级队列
- 按照一定的规则建立多个进程队列
- 不同的队列有固定的优先级(高优先级有抢占权)
- 不同的队列可以给不同的时间片采用不同的调度方法
- 存在问题:没法区分I/Obound和CPUbound;也存在一定程度的饥饿现象
- 多级反馈队列
- 在多级队列的基础上,任务可以在队列之间移动,更细致地区分任务
- 可以根据享用cpu时间多少来移动队列,阻止饥饿
- 最通用的调度算法,多数os都使用该方法或其变形
内存管理
虚拟内存
定义:具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充得一种存储器系统。其逻辑容量由内存之和和外存之和决定。
与传统存储器比较虚拟存储器有以下三个主要特征:
- 多次性,是指无需在作业运行时一次性地全部装入内存,而是允许被分成多次调入内存运行。
- 对换性,是指无需在作业运行时一直常驻内存,而是允许在作业的运行过程中,进行换进和换出。
- 虚拟性,是指从逻辑上扩充内存的容量,使用户所看到的内存容量,远大于实际的内存容量。
虚拟内存的实现有以下两种方式:
- 请求分页存储管理。
- 请求分段存储管理。
页面置换算法
操作系统将内存按照页面进行管理,在需要的时候才把进程相应的部分调入内存。当产生缺页中断时,需要选择一个页面写入。如果要换出的页面在内存中被修改过,变成了“脏”页面,那就需要先写会到磁盘。页面置换算法,就是要选出最合适的一个页面,使得置换的效率最高。页面置换算法有很多,简单介绍几个,重点介绍比较重要的LRU及其实现算法。
- 最优页面置换算法
最理想的状态下,我们给页面做个标记,挑选一个最远才会被再次用到的页面调出。当然,这样的算法不可能实现,因为不确定一个页面在何时会被用到。
- 先进先出页面置换算法(FIFO)及其改进
这种算法的思想和队列是一样的,该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予淘汰。实现:把一个进程已调入内存的页面按先后次序链接成一个队列,并且设置一个指针总是指向最老的页面。缺点:对于有些经常被访问的页面如含有全局变量、常用函数、例程等的页面,不能保证这些不被淘汰。
- 最近最少使用页面置换算法LRU(Least Recently Used)
根据页面调入内存后的使用情况做出决策。LRU置换算法是选择最近最久未使用的页面进行淘汰。
1.为每个在内存中的页面配置一个移位寄存器。(P165)定时信号将每隔一段时间将寄存器右移一位。最小数值的寄存器对应页面就是最久未使用页面。
2.利用一个特殊的栈保存当前使用的各个页面的页面号。每当进程访问某页面时,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶永远是最新被访问的页面号,栈底是最近最久未被访问的页面号。
连续型分区分配
固定式分区分配
- 内存大小固定
- 优点:容易实现
- 缺点:内部碎片比较大
可变式分区分配
- 按需分配内存
- 优点:按需分配,不存在内部碎片
- 缺点:执行过程中,产生外部碎片比较多
内部碎片与外部碎片
内部碎片:已经被分配出去的的内存空间大于请求所需的内存空间。
外部碎片:还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。
页式虚拟存储系统存在内部碎片;段式虚拟存储系统,存在外部碎片。
分区分配算法
- 首次适应算法:每次从头开始找到合适的内存进行分配。但是会导致头部内存被使用频率比较高
- 循环首次适应算法:从上次结束的位置开始找起。
- 最佳适应算法:每次拿到合适的容量进行分配
- 最坏适应算法:每次拿到最大容量进行分配
离散型分区分配
页式内存分配
- 实现:地址转换机构,页表
- 优点:没有外部碎片,程序不需要连续存放
- 缺点:页内碎片;要求程序全部放进内存,没有足够的内存就无法执行程序
段式内存分配
- 将程序按照逻辑分成大小不等的段,然后每一段就定义相对完整的逻辑信息。
- 实现:地址转换机构,段表(段号,基地址,段大小)
- 优点:程序无需连续存放,并且每一段都具有一定的逻辑关系
- 缺点:进行内存换入换出需要较长时间
段页式内存分配
- 在主存中使用段式内存分配,然后再段中使用页式内存分配
- 优势:在段式中减少内存碎片,并且保持程序的逻辑关系
- 缺点:成本高,实现复杂,由于段大小是基于程序大小来分配,因此,当大面积的内存换入换出的时候,系统会发生“抖动”。
分段式存储管理和分页式存储管理
区别:
- 段是信息的逻辑单位,他是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理内存方便而划分的,对用户是透明的。
- 段的大小不固定,由它所完成的功能决定;页的大小固定,由系统决定。
- 段向用户提供二维地址空间;页向用户提供的是一维地址空间。
- 段时信息的逻辑单位,便于存储保护和信息的共享;页的保护和共享受到限制。