深入理解操作系统- - 进程篇(1)

目录

进程解释:

process in memory(进程在内存中包含什么) :

并发的进程:

进程定义:

个人定义:

书本定义:

进程状态:

进程何时离开CPU:

内部事件:

外部事件:

进程切换:

中断源:

特权指令和非特权指令:

模式切换:

进程切换:

进程控制块:

进程在物理内存中:

 进程调度:

 实验篇

进程解释:

1)A program(程序) is a passive entity(被动的实体) , such as a file
containing a list of instructions stored on disk(often
called an executable file--可执行文件 ).---例如一个文件包含一列指令存储在磁盘
2)A program becomes a process when an executable file
is loaded into memory.(当可执行文件(指令)被加载进内存的时候一个程序就变成了进程)
3)A process is an active entity , with a program counter(pc)
specifying the next instruction to execute an a set of
associated resources.(一个进程是一个活动实体,包含一个程序计数器,规定用来指明下一条要执行的指令---pc+1加的是一个字长)

process in memory(进程在内存中包含什么) :

text:二进制代码(指令)(同一个应用程序的不同进程之间是共享程序段的)
data:全局和静态变量数据
stack:栈用于存放局部变量、函数返回地址
heap:堆用于程序 运行时 的动态内存分配
还包括pcb进程控制块
int global=100; 
void f(int x, int y){ 
 int* p = malloc(100);
 return; 
} 
void g(int a){ 
 f(a, a+1); 
 return;
} 
int main() 
{ 
 static int i=10; 
 g(i); 
 return 0; 
}

将程序加载入内存

代码的二进制指令全部放入text区--------存放的指令是只读的

先执行main函数指令  将main函数的返回地址写入栈(stack)中

发现一个全局变量和一个静态变量放入data区(编译好的代码是有全局观的,所以会知道有全局变量)

调用函数g(), 把g()函数的局部变量放入栈中,并把函数的返回值压入栈中,

调用f()函数,把f函数的局部变量x,y,p放入栈中,再将f()函数的返回值放入

f()函数申请的动态内存放入heap,申请的空间内存的首地址赋值给p指针

从stack栈中得到f()函数的返回地址,让后出栈,同时函数清理需要把该函数的所有变量从栈中清掉。

取出g()函数返回地址,清空g()函数

取出main()函数的返回值,并清空栈中与data区中的数据

heap中的内存必须手动回收

并发的进程:

Concurrency:the fact of two or more events or
circumstances happening or existing at the same time.
(并发:两个或多个事件的事实同时 发生或存在的情况---不是同时runing运行--并行)

进程定义:

个人定义:

进程是一个拥有cpu使用权的进行计算任务的基本单位。

书本定义:

进程是一个程序的一次执行过程
能完成具体的功能
是在某个数据集合上完成的
执行过程是可并发的
进程是资源分配、保护和调度的基本单位

进程状态:

进程在执行期间自身的状态会发生变化,进程有三 种基本状态,分别是:
运行态(Running) :此时进程的代码在CPU上运行(正在执行的才是运行态)
就绪态(Ready) :进程具备运行条件,等待分配CPU
等待态(Waiting) :进程在等待某些事件的发生(比如 IO操作结束或是一个信号)(不具备运行条件)

进程何时离开CPU:

内部事件:

进程 主动放弃(yield) CPU,进入等待/终止状态。
E.g 使用I/O设备(等待),(非)正常结束(终止)。

外部事件:

进程被剥夺CPU使用权,进入就绪状态。这个动作叫 抢占(preempt)
E.g 时间片到达,高优先权进程到达。
new是一个新建状态,将程序加载入内存的状态
当运行除了cpu之外的所有资源都就绪后进入就绪态
当得到cpu权限后进入运行态,当运行完成后进入terminated状态
(被动)在运行态cpu被抢夺后进入就绪态
(主动)在运行态使用I/O设备的时候进入等待状态  等待结束重新进入就绪状态

进程切换:

并发进程中,一个进程在执行过程中可能会被另一个进程替换占有CPU,这个过程称作“进程切换” 

中断源:

外中断:

来自处理器之外的硬件中断信号

如时钟中断、键盘中断、外围设备中断 外部中断均是异步中断

内中断(异常 Exception):

来自于处理器内部,指令执行过程中发生的中断,属同步中断

硬件异常:掉电、奇偶校验错误等

程序异常:非法操作、地址越界、断点、除数为0

系统调用

(参考书籍不同定义就不同---内中断应该只是说法不同 可能依次对应 终止、异常、陷入)

Exception(内)与interrupt(外)统称中断,发生中断后保存进程的上下文信息(相当于快照)(pc---在上边说到程序转换成了二进制指令,不止pc)执行中断处理程序(进入内核),选择对应进程进行恢复进程上下文,返回进程的执行。

特权指令和非特权指令:

Privileged Instructions
The Instructions that can run only in Kernel Mode are called Privileged Instructions .
*I/O instructions and Halt instructions(I/O指令/停止指令)
*Turn off all Interrupts(关闭中断)
*Set the Timer  (设置时钟定时器)
*Process Switching  (进程切换)
Non-Privileged Instructions
*The Instructions that can run only in User Mode are called Non-Privileged Instructions .
怎么区分特权指令和非特权指令?
通过硬件,设置一个比特位

模式切换:

*中断是用户态向核心态转换的唯一途径!系统调用 实质上也是一种中断。
*OS提供Load PSW指令装载用户进程返回用户状态

进程切换:

1)在进程切换的第一步将cpu的user mode 切换到核心 mode 
2)保存被中断进程的上下文信息

3)修改被中断进程的控制信息(如状态等)

2、3两步会保存到该进程的PCB进程控制块,当重新得到cpu的控制权的时候会将PCB进程控制块加载到cpu

4)将被中断的进程加入相应的 状态队列
5)调度 一个新的进程并恢复它的上下文信息

进程控制块:

每个进程都拥有一个自己的PCB进程控制块

A Process Control Block(PCB)contains many pieces of information associated with a specific
process.(一个进程控制块包含很多信息,与一个特定的进程有关)

进程在物理内存中:

进程的进程实体并不是整体存放,而是离散存放
管理进程使用的是进程队列进行管理:
只有俩个状态--ready(就绪)/等待状态,运行态没用队列只有一个
就绪状态队列是使用链表进行连接形成队列(只是连接的pcb),当某个队列需要进入runing状态则从就绪队列中移除

 进程调度:

  进程在整个生命周期中会在各个调度队列中迁移, 由操作系统的一个调度器(scheduler)来执行

这里的主动与被动是相对于自身发生的事件来观察的

eg:当I/O请求发生后cpu是主动离开 

当时间片结束是操作系统剥夺cpu的执行权,被动

创建子进程,调用wait函数进行等待,当子进程结束后主动离开

等待中断,当中断发生后立即交出cpu的执行权。

 实验篇:

Practice: How to create a child process?

这个实验在上一年学习Linux编程技术的的时候已经做过该实验,在这进行简单实验,若需要详细了解函数的原理可以查考Linux编程技术专栏。

补充:

调用fork()后,会把整个进程的信息进行copy完全复制给新创建的子进程,且两者的内存空间是相互独立的,在fork()后父子进程并发执行后边的程序,在子进程中fork函数的返回值为0,在父进程中会返回子进程的pid。(这里的并发可以根据打印信息的程序来判断--会无规律的进行交替打印)

getppid()函数是获得当前进程的父进程的pid(注:如果父进程在子进程结束之前结束,则子进程变成孤儿进程,则需要找1号进程(是系统启动的第一个进程INITD)作为父进程,即托管给系统进程)

为了避免孤儿进程的发生,我们引入了wait(NULL)方法,该方法作用与父进程,让父进程等待子进程结束后再返回。  

 代码如下: