关于fork进程创建和进程上下文切换时现场保存的个人理解

本文针对以下三个容易混淆和出错的问题:

(1)Unix系统中用fork()创建新进程时,要复制父进程内存,父进程的页表是不能完全复制的吧?

(2)进程切换过程中的上下文信息保存与恢复,必须在内核态吗?

(3)信号量和管程机制是否可以相互实现,有没有确定的答案和证明?

首先理解以下概念:

一、进程控制块

进程控制块:PCB是操作系统管理控制进程运行所有的信息集合,主要包括进程描述信息、进程控制和管理信息、资源分配清单和处理机相关信息等,是进程实体的一部分,进程存在的唯一标志。

PCB是进程在内存中的静态存在方式,因此进程的静态描述符必须保证一个进程在获得CPU并重新进入运行态时,能够精确的接着上次运行的位置继续运行,相关的程序段、数据以及CPU现场信息都要保存下来,CPU的现场信息主要包括内部寄存器和堆栈的基本数据。

二、进程上下文

进程上下文:当程序执行了系统调用或中断而进入内核态时,进程切换现场就称为进程上下文,包含了一个进程所具有的全部信息,一般包括:进程控制块(PCB)、有关程序段和相应的数据集。

三、进程堆栈

进程的堆栈:内核在创建进程的时候,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。

进程用户栈和内核栈的切换:当进程因中断或系统调用而陷入内核态运行时,进程所使用的堆栈也要从用户栈转到内核栈。

进程进入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,完成用户栈向内核栈的转换;当进程从内核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器,实现内核栈和用户栈的互转。

那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的,但是在陷入内核的时候,我们是如何知道内核栈的地址的呢?

关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是因为,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态运行的相关信息,但是一旦进程返回到用户态后,内核栈中保存的信息无效,会全部恢复,因此每次进程从用户态陷入内核的时候得到的内核栈都是空的。所以在进程陷入内核的时候,直接把内核栈的栈顶地址给堆栈指针寄存器就可以了。

对三个问题的分析如下:

(1)Unix系统中用fork()创建新进程时,要复制父进程内存,父进程的页表是不能完全复制的吧?

解析:

Unix进程创建系统调用fork()在创建一个继承的子进程时,需要复制父进程的相关信息,包括父进程的所有变量和内存、父进程的所有cpu寄存器。但是父进程在创建子进程时,肯定会创建子进程的PCB和内核堆栈等与父进程不一样的信息,这些信息在内存中的页面与进程是不一样的,因为父进程的页表存储的是父进程的内存地址空间,既然子进程的内存地址空间发生了变化,子进程就不能完全复制父进程的页表。

 

(2)进程切换过程中的上下文信息保存与恢复,必须在内核态吗?

解析:

用户进程既有用户空间信息也有内核空间信息,在进程切换过程中,进程的所有信息都要保存,但用户空间的信息(用户堆栈、用户数据等)是保存存在用户空间,传递地址给内核,只有内核空间的信息保存在内核态。因此,我的理解是进程切换肯定是要内核参与,但上下文信息并非全部保存在内核空间。

鉴于此,一、进程切换时的现场保存一定在内核中的进程控制块中;二、进程切换的现场保存必须在内核态。这两种说法都是不对的。

(3)信号量和管程机制是否可以相互实现,有没有确定的答案和证明?

解析:

信号量和管程机制在使用上可以等价,可以基于一种机制来实现另外一种机制,具体实现和证明咱略。

鉴于自身对操作系统的理解有限,对概念和问题的解析若有不足之处,欢迎留言指正。

猜你喜欢

转载自blog.csdn.net/feixuedongji/article/details/79287891