进程切换中的惊险一跳

来源:互联网 发布:windows部署git服务器 编辑:程序博客网 时间:2024/04/29 09:41

总以为在进程切换的过程中,有所谓的经常惊险一跳,因为代码的运行离不开栈数据的使用和其他数据(全局、静态、堆)。当时粗浅地知道系统调用会产生一个系统堆栈,所以就特别疑惑,如果程序是一条指令一条指令运行,栈切换,如果反映为多步的话,它指令也是一条条执行,那么在切换栈的某一时期可能会存在栈混用或栈不可用的情况,所以,切换地方的代码需要特殊的编制才可以避免混乱,连半步都不能错,会有“惊险”的一跳存在!!


有了这个惊险的一跳的疑惑后,就跟一位公司的Linux大侠讨论过一次,他转发过来linux源代码,证明说,在切换的过程中“一切都很自然,不存在惊险的一跳”。但是,关于这个地方的理解,自己还是费了一些功夫,搜索了一些资料,最后将眼睛定睛在自己网上搜索到的PPT资料Context Switch In Linux和扩展linux系统调用,看了很久、很久,不断地组织、摸索和与人探讨,最后才看出一点门道,特别是在X86 CPU下进程切换是怎样一个大致步骤有点理解了,现在整理这个理解步骤如下:

1、程序在内存的映像
程序在内存的映像分为用户空间部分和操作系统空间部分,而且操作系统空间部分为各个进程所共享。这样,操作系统空间内存逻辑地址对所有的进程是一致的。即在操作系统内核态的一个逻辑地址,在各个进程中如果类似作为全局变量来传递信息的话,它所对应的物理内存地址也是一致的。所以,操作系统代码访问系统空间内的代码、栈数据和全局/静态/堆数据,具有惊人的一致性,根本不存在任何显著的“切换”,都是在操作自己的统一一致的地址。

2、用户栈和系统栈切换的原子性
在X86 CPU上用户栈和系统栈切换具有原子性,这样一个特点破除了自己关于“惊险”一跳中,一个重要的基础,即认为切换栈的代码分多步指令,可能会存在栈混用。在具体的操作中,通过一个指令既可以完成用户栈到系统栈的转换,是具有“原子性”的。

在X86中这个切换靠TSS信息,不过这个影响不大,我们可以认为在任何CPU都存在如此原子性的一步。

PS:而在这个指令和与其相配合的代码,也会在系统栈上保存用于回到用户态的信息,例如程序执行指令计数器。

3、系统栈
关于进程的系统栈,是一个操作系统空间内的一块内存区域,由第一条的知识,我们知道它对所有进程来说,它所对应的逻辑地址与物理地址都是一致。只是由于用户态和核心态的隔离,其它进程不可能操作这块内存区域,只是在核心态的代码才能去访问。所以,不同进程,如果该进程存在着系统栈,那么他们都是操作系统空间内的一块区域,只是不同的操作系统空间上的地址,但这个地址对于所有进程具有一致性。

4、由一个系统栈切换到另一个进程的系统栈

由于系统栈栈顶指针只是一个操作系统空间的一个地址,所以,核心态的代码从操作系统空间的数据(全局或静态或堆)中取出另一个进程的系统栈栈顶指针,将栈顶指针寄存器一换,即可切换到另外一个进程的系统栈。


5、回到另一个进程的执行

  系统栈退完再加上原子性切换系统栈到用户栈就可以再次回到另一个进程的执行

   其实,本人最开始由惊险一跳的疑惑时,是想着在切换的关键步骤上,用户态和核心态不管是在代码、在(全局/静态/堆)数据还是在栈数据都可能会存在混用的状态。不过,由第一条知识后,只是稍微对栈的混用疑惑!后来,用户栈到系统栈的原子性跳跃,也更深一步地击破了自己的疑惑。
   
   原来有惊险一跳的想法是因为马克思在商品经济学中所说的,商品在实现其价值的时候,存在惊险的一跳,那么在进程切换的过程中,能不能切换过去,是否也如此惊险呢?有令人担心的一跳呢?呵呵,现在想来确实如那个大侠所言,一切都很自然。。。。

   其实在前一段自己很不看好弄懂进程切换的过程,认为只要能够确定一个算法过程,那个问题实际上是解决的。由于进程切换已经实现,肯定就是一个确定的算法过程,那么就不值得自己花很多时间去弄清楚。但是,现在觉得,弄清楚后的感觉还不错,呵呵,加深了自己对于计算机的一些理解。

   另外,用户空间映射关系在进程转换过程中也会被切换,但是由于切换过程的代码,很多时候是操作的是操作系统空间的数据和代码,所以,用户空间,特别是数据(全局/静态/堆)和代码只是其中一个很不起眼、甚至不重要的过程,做的靠前或靠后都影响不是很大,至少个人是这样认为的,呵呵!


   奇文共欣赏,疑义相与析,获得了理解之后,痛苦有一次后就不想让别人再受一次,所以就有这篇目的以一种更容易理解的方式解释这个过程的文章,欢迎探讨:)

原创粉丝点击