操作系统中最核心的概念是进程:这是对正在运行程序的ー个抽象
并行 并发
“在任何多道程序设计系统中,CPU由一个进程快速切换至另ー个进程,使每个进程各运行几十或几百毫秒。严格地说,在某ー个瞬间,CPU只能运行ー个进程。但在1秒钟内,它可能运行多个进程,这样就产生并行的错觉。有时人们所说的伪并行就是指这种情形,以此来区分多处理器系统(该系统有两个或多个CPU共享同一个物理内存)的真正硬件并行”
- 并行(Parallelism)与并发(Concurrency):
- 并行指的是多个任务在同一时刻同时执行。这通常发生在多核或多处理器系统中,不同的处理器可以同时执行不同的任务。
- 并发则是指多个任务在一段时间内交替进行,从宏观上看好像同时发生,但实际上同一时刻只有一个任务在执行。在单核系统中,通过快速的任务切换实现这种效果。
- 时间分片(Time Slicing):在单处理器系统中,操作系统通过将CPU时间分配给不同的进程,让每个进程运行一小段时间(时间片),然后迅速切换到下一个进程。由于切换速度很快,给人的感觉是所有进程都在同时运行。
- 抢占式调度(Preemptive Scheduling):操作系统可以根据需要中断当前正在执行的进程,转而执行另一个进程。这种机制进一步增强了并发执行的效率和响应性,但每个进程仍然是交替执行的。
因此,当说“进程本质上是不可能做到真正的并行,只是切换的速度极快以至于产生并行的假象”时,这句话主要针对的是在单处理器环境下的情况,或者虽然在多核处理器环境下,但考虑到某些限制(如进程绑定到特定核心,或因资源竞争导致的阻塞)使得并非所有进程都能真正并行执行。在多核系统中,虽然存在真正的并行执行能力,但单个进程内的线程或其他任务之间仍然可能通过上述机制实现并发执行,而非所有部分都并行运行。
在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干顺序进程(sequentialprocess)»简称进程(process)oー个进程就是ー个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。
进程和程序
进程和程序间的区别是很微妙的,但非常重要。用ー个比喻可以更容易理解这一点。想象一位有ー手好厨艺的计算机科学家正在为他的女儿烘制生日蛋糕。他有做生日蛋糕的食谱,厨房里有所需的原料:面粉、鸡蛋、糖、香草汁等。在这个比喻中,做蛋糕的食谱就是程序(即用适当形式描述的算法),计算机科学家就是处理器(CPU),而做蛋糕的各种原料就是输入数据。进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等ー系列动作的总和
。
一个进程是某种类型的一个活动,它有程序,输入,输出以及状态。
守护进程
守护进程(Daemon Process)是在类Unix操作系统(如Linux、macOS等)中的一种后台运行的系统程序,它独立于用户终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程不与任何终端关联,通常是在系统启动时启动,并一直运行直到系统关闭。它们常用于执行如下类型的任务:
- 系统服务:如打印队列管理、邮件服务、网页服务器、数据库服务等,这些服务需要长期运行并随时响应系统或网络请求。
- 任务调度:执行定时任务,如cron守护进程,它可以按照预定的时间安排运行用户或系统的脚本和程序。
- 日志记录:监控系统活动并记录日志,例如syslog守护进程负责收集并记录系统日志。
- 资源监控:监控系统资源使用情况,如检测磁盘空间使用、内存占用等,并在必要时采取行动或发出警告。
- 作业管理:管理用户提交的后台作业,确保它们在系统中正确排队和执行。
守护进程的特点包括:
- 无终端:它们在后台运行,没有控制终端,也不与任何用户交互。
- 长期运行:设计为长时间甚至无限期运行,除非被专门停止或系统重启。
- 后台启动:通常由系统在启动时自动启动,也可以由管理员手动启动。
- 低交互性:除了通过特定接口(如网络端口、配置文件或信号)接收指令外,它们不直接与用户交流。
创建守护进程通常涉及以下步骤:
- fork:进程首先通过fork()系统调用创建一个子进程,然后父进程退出,这样子进程就变成了孤儿进程,由init进程接管。
- setsid:子进程调用setsid()成为新会话的首进程,与原来的控制终端分离。
- 重定向标准输入输出:通常将标准输入、输出和错误重定向到 /dev/null 或特定的日志文件,避免占用终端或产生不必要的输出。
- umask设置:调整文件权限掩码,确保守护进程创建的文件具有合适的权限。
- 工作目录更改:通常将工作目录更改为根目录 /,避免因当前工作目录被卸载而引发的问题。
通过这些步骤,进程就可以作为守护进程在后台稳定运行,默默地执行其预定任务。
进程的创建
创建条件
1)系统初始化。
2)正在运行的程序执行了创建进程的系统调用。
3)用户请求创建一个新进程。
4)一个批处理作业的初始化。
UNIX系统中,通过fork系统调用来创建新进程,生成一个与父进程相同的副本。之后,子进程常通过exec系列系统调用来替换自身内存映像并执行新程序,这允许在进程创建与程序执行之间进行设置调整,如重定向I/O。
相比之下,Windows系统使用CreateProcess函数一步完成进程创建与程序加载,该函数具备更多参数以细致控制进程属性、安全、文件继承、优先级及窗口配置等,体现了更为直接和全面的进程管理能力。此外,Windows的Win32
API提供了大约100个其他函数来辅助进程管理、同步及关联操作。
进程的终止
1)正常退出(自愿的)。
2)出错退出(自愿的)。
3)严重错误(非自愿)。
4)被其他进程杀死(非自愿)。
进程的层次结构
某些系统中,当进程创建了另ー个进程后,父进程和子进程就以某种形式继续保持关联。子进程自身可以创建更多的进程,组成一个进程的层次结构
进程只有一个父进程(但是可以有零个、ー个、两个或多个子进程)
initi()
在UNIX和Windows中,进程创建之后,父进程和子进程有各自不同的地址空间。如果其中某个进程在其地址空间中修改了一个字,这个修改对其他进程而言是不可见的e在UNIX中,子进程的初始地址空间是父进程的ー个副本,但是这里涉及两个不同的地址空间,不可写的内存区是共享的。某些UNIX的实现使程序正文在两者间共享,因为它不能被修改。或者,子进程共享父进程的所有内存,但这种情况下内存通过写时复制(copy-on-write)共享,这意味着一旦两者之一想要修改部分内存,则这块内存首先被明确地复制,以确保修改发生在私有内存区域。再次强调,可写的内存是不可以共享的。但是,对于ー个新创建的进程而言,确实有可能共享其创建者的其他资源,诸如打开的文件等。在Windows中,从ー开始父进程的地址空间和子进程的地址空间就是不同的。
进程的状态
1)运行态(该时刻进程实际占用CPU)。
2)就绪态(可运行,但因为其他进程正在运行而暂时停止)。
3)阻塞态(除非某种外部事件发生,否则进程不能运行
进程的实现
为了实现进程模型,操作系统维护着ー张表格(ー个结构数组),即进程表(processible)。毎个进程占用一个进程表项。(有些作者称这些表项为进程控制块°)该表项包含了进程状态的重要信息,包括程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息,以及其他在进程由运行态转换到就绪态或阻塞态时必须保存的信息,从而保证该进程随后能再次启动,就像从未被中断过ー样
一个进程在执行过程中可能被中断数千次,但关键的是每次中断后,被中断的进程都返回到与中断发生前完全相同的状态。
多道处理模型
这段内容主要讨论的是多道程序设计(Multiprogramming)如何通过增加并发运行的进程数量来提升CPU利用率,并且探讨了如何从概率角度来理解CPU利用效率与I/O等待时间的关系。下面我将尽量用通俗的语言来解释这段内容。
多道程序设计的目的
多道程序设计是一种操作系统技术,它允许计算机同时加载多个程序到内存中,并且在它们之间切换执行,即便这些程序没有全部准备好运行(比如有些在等待输入输出操作)。这样做主要是为了提高CPU的使用效率,因为在任何给定时刻,如果有进程因为等待I/O(比如从硬盘读取数据或用户输入)而暂停,CPU就可以转而去执行其他准备好的进程,从而减少CPU空闲的时间。
CPU利用率的决定因素
CPU利用率指的是CPU正在执行任务的时间占总时间的比例。如果一个进程大部分时间都在等待I/O,那么CPU就会有很多空闲时间。这里引入了一个比例P,表示一个进程等待I/O的时间占其在内存中总时间的比例。如果P是80%,意味着一个进程有80%的时间在等待I/O,只有20%的时间在真正计算。
道数(Degree of Multiprogramming)的影响
“道数”指的是同时在内存中的进程数量。随着道数n的增加,理论上CPU空闲的可能性会降低,因为更有可能在某个进程等待I/O时,有其他进程处于就绪状态,可以立即使用CPU。但实际情况要复杂一些,因为所有进程同时等待I/O的概率(记作p^n)也会上升,这会降低CPU的利用率。
简化的模型与实际情况
文章提到了一个简化的模型来估算CPU利用率,即CPU利用率 = 1 - P^n。这个公式假设了所有进程是独立的,且CPU可以瞬间从一个进程切换到另一个。但实际上,由于单CPU环境下同一时间只能执行一个进程,因此这个模型忽略了CPU调度的延迟和开销,以及进程之间因争夺资源(如CPU时间片)而产生的潜在等待。
实例分析
举例说明,假设每个用户程序需要2GB内存,操作系统占用2GB,共8GB内存。在这种配置下,最多能同时运行3个用户程序。如果P=80%,即每个进程80%的时间在等待I/O,那么CPU利用率大约是49%。增加内存至16GB,可以支持7个程序同时在内存中,此时CPU利用率提高到约79%。进一步增加内存到24GB,CPU利用率提升至约91%。
结论
这个模型说明,起初增加内存可以显著提升CPU利用率和系统吞吐量,因为从几乎无法有效利用CPU(3个进程时)转变为较为高效的利用(7个进程时)。但随着内存的持续增加,边际效益递减,即每增加相同的内存量,对CPU利用率的提升效果越来越小。因此,第一个8GB内存的升级是非常划算的,因为它带来了巨大提升;而之后的内存增加,虽然也能提高性能,但性价比逐渐降低。这就是为什么说“第一次增加内存是划算的投资,而第二个则不然”。
为了更好地理解这个公式 CPU 利用率 = 1 - P^n 的推导过程,我们可以从概率的角度逐步分析,这里我们将利用互斥事件的概率计算原理。请注意,这里的推导基于一定的简化假设,比如进程之间的等待是完全独立的,实际上的系统行为可能更为复杂。
基础概念
- P:单个进程在单位时间内处于I/O等待状态的概率。
- 1-P:单个进程在单位时间内处于CPU计算状态的概率。
- n:同时在内存中的进程数量。
- P^n:所有n个进程同时处于I/O等待状态的概率。
- CPU利用率:CPU实际执行任务的时间占比。
推导步骤
- 单个进程的行为分析:
- 一个进程在任何给定时间点要么在执行CPU计算,要么在等待I/O。如果一个进程在单位时间内I/O等待的概率是P,那么进行CPU计算的概率就是1-P。
- 多个进程同时等待I/O的概率:
- 当有n个独立的进程时,所有这些进程同时处于I/O等待状态的概率是各个进程独立事件同时发生的概率乘积,即P^n。这是因为每个进程是否等待I/O是独立的,第一个进程等待的概率是P,第二个进程也是P,以此类推,n个进程同时满足这个条件的概率就是P的n次方。
- CPU空闲的概率:
- 如果所有n个进程都恰好在等待I/O,那么CPU在这段时间内是空闲的。因此,CPU空闲的概率就是所有进程同时处于I/O等待状态的概率,即P^n。
- CPU忙碌的概率与利用率:
- 既然CPU空闲的概率是P^n,那么CPU忙碌的概率就是1减去空闲的概率,即1 - P^n。因为CPU利用率定义为CPU处于工作状态的时间比例,所以CPU利用率 = 1 - P^n。
总结
通过上述分析,我们可以看到,公式CPU利用率 = 1 - P^n是从概率论的角度出发,考虑了所有n个进程同时处于I/O等待状态的概率,并据此反推出CPU实际被利用的概率,即利用率。这个公式体现了多道程序设计中通过增加并发进程数量来降低所有进程同时等待I/O概率,从而提升CPU使用效率的核心思想。