下面的整理也是自己最近看的《计算机操作系统设计与实现 第三版》的内容后 自己理解的一些东西 记录下
这里主要是自己理解的进程一些内容 可能和实际有误~~~
先来理解下2个名词
寄存器:寄存器是中央处理器的一分部 在计算机领域中 寄存器是CPU的内部元件用来暂时存放指令 数据 和地址的地方程序计数器:用来存放下一条指令所在单元地址的地方。当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令
进程的概念
在计算机操作系统 进程是对正在运行的程序的抽象
简单点讲 一个正在运行的程序就是一个进程(processes),其中包括了他的寄存器 程序计数器,变量的值 堆栈等等。
比如打开一个word 打开一个QQ 打开一个网易云音乐 这些都是一个进程
进程模型
计算机中所有可运行的软件(包括操作系统)被组织成若干顺序进程 也就是进程 他使得并行更容易处理(其实是伪并行吧 因为真正的CPU会在进程之间来回切换 来运行进程 只是速度非常快 让人们感觉不到切换 以为是并行处理的)
比如上面的例子 有4个进程 分别是 A、B、C、D 每个进程都有自己的程序计数器 和自己的处理逻辑 每个都是独立的 CPU在执行的时候会在他们之间来回的切换 当然最外面的物理计数器只有一个 当CPU执行到进程A的时候回把A的程序计数器给最外面的物理计算器然后运行 当CPU决定要切换到下一个进程的时候 (例子中就是B了)先把当前进行了的计数器重新还给进程的A的程序计数器 然后物理计算器在获取进程B的程序计数器继续执行 后面同理 每个进程的处理速度都不一样 当然也会有优先级问题 这些就是CPU的切换算法涉及的一些东西 不是很懂了这个
进程的创建
一般来讲会有下面4种情况会创建进程
- 系统初始化
- 一个进程调用了创建进程的系统调用
- 用户请求创建一个进程(比如用户在终端启动一个编译器)
- 批处理作业的初始化(这种情况可能我们没有接触过,主要就是在大型机的批处理操作会一次提交批处理作业 当操作系统认为有足够的资源来处理另外一个作业的时候就会启动一个进程来处理 这种系统我是没见过 囧~)
进程的终止
一般来讲 进程的终止也有4种情况
- 正常退出(自愿)–这种情就是进程执行完了自动退出
- 出错退出(自愿)–这种就是进程出现了错误 比如
cat xx.file
当 xx.file 不存在的时候直接退出 - 严重错误(非自愿)–这种就是编译我们的代码,代码里有严重的错误
- 被其他进程杀死(非自愿)
进程的状态
每个进程都是一个独立的实体。有他自己的程序计数器、堆栈、打开的文件、定时器、和内部状态等。当进程的在执行的时候有下面3中状态
- 运行态(Running 在这个时候是真正占用了处理机(比如CPU))
- 就绪态(Ready 可运行,但是因为其他进程在运行他被暂时挂起)
- 阻塞态(Blocked 这种时候除非某种外部事件发生,否则不能运行)
前面2中状态下 其实都可以运行 只是后者中暂时没有CPU分配给他.
第三种状态下不可运行 即使把CPU资源分配给了他也不可运行.
- 上面是一个进程状态转换图 下面来举例说明一下
- 转换1由运行态—->阻塞态 这种情况是进程发现自己无法继续运行下去
比如一个进程需要从终端读取输入才可继续运行 而终端一直没有输入 进程会发生这种转换 - 转换2和转换3 是由系统调度器来控制的,系统调度器是操作系统的一分部我们感觉不到(进程自己都感觉不到!!)
当处理机任务当前进程进程占用的时间已经够长 决定让其他进程来执行的时候 会发生转换2 把当前进程的由运行态转换成就绪态。
当系统调度器任务其他进程已经占用了够多的时间 重新轮换到当前进程来执行的时候他就会发生转换3 把进程的就绪态转换成运行态来继续执行当前的进程 - 当一个进程等待外部时间发生时 发生转换4 比如到达了一些外部输入
科普下调度器的只要功能:它主要用来决定当前那个进程可以运行(占用CPU资源)以及进程可以运行多长时间。现在已经有很多种成熟的算法来平衡系统的调用 这些东西就不是我所理解的范围了 囧
进程的实现
为了实现进程模型 系统维护着一张表 这个表就是进程表(processes table)每个进程占用一个表项(个人理解相当于一个数据库表的一条记录吧)。这些表项包含了进程的状态,他的计数器、栈指针、内存分配状况、打开文件状态、统计和调度信息、定时器和其他信号 以及他由运行态到就绪态转换所需要保存的其他信息(个人理解这些信息就相当于数据库表的字段 或者属性一样的东西吧)。这些信息是为了让他再次运行的时候像未中断过一样。
在一些系统中进程通信、内存管理、文件管理是由几个不同的模块来管理的 然后他们就把进程表给分割开了 也就是他们各自维护了进程表的一些信息(相当于上面的字段吧)
下面来举例说明一台有单个CPU 多个I/O设备的计算机如果维护多个顺序进程(也就是进程)来做更多的解释。
假设当一个磁盘发生中断(其实就是cpu从当前进程切换到别的进程)时 用户进程(id 23)正在运行,则中断硬件将当前的程序计数器、程序状态字以及可能的一个或多个寄存器压入当前堆栈 计算机立即跳转到中断向量多指定的地址处,这些步骤都是硬件做的处理(至于硬件怎么实现的并不关心估计也是电气工程学)。后面软件就接管了后续的操作。中断服务的过程从全部寄存器压入堆栈开始,当前“进程号”(这个例子里就是23)及一个指向其表项的指针被保存在全局变量中 这是为了能够迅速找回他们,随后将中断存入的那部分信息从堆栈中删除,并将栈指针指向一个被进程处理程序(这里应该是刚刚23号处理中所占用的堆栈)所使用的临时堆栈,然后调用一个C过程来处理特定中断剩下的工作。一般进程间通信是通过消息完成的(管道也可以) 下一步构造一条发送给磁盘进程的消息 这时磁盘进程正被阻塞等待该消息的到来。这条消息说发生了一条中断,以此来区分别的用户的读磁盘消息(因为现在中断了但是还会有别的用户正发送读取的操作啊),现在磁盘状态由阻塞态转为就绪态然后中断服务器调用调度器来完成调度 决定是中断(继续执行当前进程)还是给别的用户读取(也就是别的进程) 下面是一个中断处理的大概执行过程 不同的操作系统可能会有所不同
线程的概念
- 在传统操作系统中,每个进程只存在一个地址空间和一个控制流 这个控制流就是线程(thread)。有些情况下需要在同一个地址空间中有多条控制流并行的运行 就像他们都是单独的进程一样(其实他们只是共享地址空间)这些多个控制流就是–多线程
- 进程中有一个存放程序正文和数据以及其他资源的地址空间。这些资源包括打开的文件、子进程、未处理的定时器、信号处理器和审计信息
- 进程具有另外一个重要的概念就是执行流 — 也就是线程
- 线程有一个程序计数器 用来跟踪下一个将要执行的指令
- 线程有寄存器 用来存储当前使用的变量
- 线程有堆栈 用来存储执行的历史 其中每一栈帧保存了没有返回的过程调用
尽管线程需要在进程中执行,但进程和线程是可以分别对待的2个不同的概念,进程是用来进程资源整合而线程是CPU调度的实体
这个图展示了一个在用户空间 三个进程各有一个线程 和 一个进程包含3个线程
这个是每个进程和线程的一些区别
另外在一些系统中 操作系统是知道每个进程有多少线程的,所以当一个线程阻塞时 系统会选择下一个线程来运行 这些线程可能来自同一个进程 也可以是不同的线程。为了进行调度内核必须有一张线程表 记录所有的线程 这个就与进程表类似了
CPU在线程之间切换时是有损耗的 因为他需要保存进程的状态 寄存器之类的信息 以便下次运行该进程的时候可以无缝衔接就像未中断过一样,虽然是在进程间切换但是进程下面又细分出了线程 所以也可以说是在线程之间切换的,这就产生了两种方式
一种是把线程管理放在用户空间 因为在用户空间切换速度比内核调用的情况速度要快的多(为什么用户空间比内核调用快呢?这里还真不是很清楚!!!!)
用户线程和内核线程的区别主要表现在性能上。用户线程切换只需要几条指令,而内核线程的切换需要完成的上下文切换,修改内存映射,使高速缓存失效,这将比用户线程慢了几个数量级 这里有篇博客写的很详细
另一种是把线程管理放在内核。因为如果把线程全部放在用户空间管理 如果一个线程发生了阻塞 则内核将整个进程阻塞 因为内核根本不知道其他线程的存在 也就无法调度到其他的线程上
无论选择哪种方式都有一大堆问题需要解决 这里不是我们要涉及的范围了 估计又可以搞几本书了(恐怕还不止!!)
本人理解有限 大概只能理解这么多了 先这样吧 有空在挖下!