zoukankan      html  css  js  c++  java
  • fork、父进程和子进程

    进程

    什么是进程?进程是一个运行中的程序实体,拥有独立的堆栈、内存空间和逻辑控制流。

    这是标准的进程概念。让我们通过操作系统的fork函数看看这个抽象的概念是怎么在进程的实现中体现出来的。

    构成要素

    创建一个进程,需要进程体、进程表和数据空间。

    进程体在C代码中对应一个函数,编译成二进制代码后就是一组指令。

    进程表用来记录进程的进程ID、进程名称、寄存器快照空间。简单说,当中断发生时,会保存此刻CPU的状态,然后记录到进程表中。

    进程表的作用就是用来存储进程快照。

    进程堆栈的作用是什么?存储进程中函数的参数,存储进程运行过程中的局部数据。

    数据空间呢?先看一段简单的代码。

    char *f(int a, int b);
    
    int main(int argc, char **argv)
    {
      	f(5, 6);
      
      	return 0;
    }
    
    char *f(int a, int b)
    {
      	int c = a + b;
      	char *str = "Hello, World!";
      	return str;
    }
    
    1. 两个参数a和b存储在进程的堆栈中。
    2. 指针char *str指向的内存中的数据STR存储在进程的数据空间中。

    为什么STR不是存储在进程的堆栈中呢?

    函数f的返回值是STR的内存地址。执行这段代码,我们会发现:调用函数f能正确获得STR。

    试想一下,假如STR存储在进程的堆栈中,当f执行结束后,堆栈中的数据会被清空,我们调用函数f是不能正确获得STR的。

    STR存储在进程的数据空间中,存储在进程堆栈中的只是存储STR的内存空间的内存地址。

    fork

    进程A调用fork新建进程B,A是B的父进程,B是A的子进程。

    fork执行结束后,如果能成功创建B进程,B进程的数据空间、堆栈和进程表和A进程的这些要素完全相同。

    差异

    B进程毕竟是不同于A进程的独立进程,所以:

    1. B进程的数据空间中的数据和A进程的数据空间的数据一致,但是,两个进程的数据空间却是不同的内存空间。
    2. B进程表中,指向LDT的选择子和A进程表中的LDT选择子不同。
    3. B进程表中的进程ID和A进程表中的进程ID不同。

    堆栈

    猜猜看,子进程的堆栈是在进程表中还是在数据空间中?

    回答是:在进程的数据空间中。

    在前面,我们虽然把堆栈和数据空间分开说,那是为了强调两个要素在保存数据时的差异。堆栈中的数据随时变化,例如,进程中的一个函数执行结束,堆栈中的数据就会发生变化。

    进程的数据空间呢?我以为,当进程结束执行的时候,进程的数据空间中的数据才会消失。这是我的猜测,暂时不知道怎么去验证。

    认为堆栈保存在数据空间中的依据是什么?因为寄存器ss中的选择子指向的描述符描述的那段内存空间就是数据空间。

    进程的ds、es、ss的选择子相同,指向相同的数据空间。

    LDT、GDT和LDT选择子

    每个进程都有一个LDT。LDT存储在进程的进程表中。

    在进程的进程表中,有一个LDT选择子。根据LDT选择子,能从GDT中找到指向LDT的描述符。

    有点绕。连起来再说一次:通过进程表中的LDT选择子,从GDT中找到指向LDT的描述符,根据描述符找到LDT,LDT也在进程表中。

    我的收获

    1. 进程的堆栈存储在进程的数据空间中。
    2. 堆栈是动态变化的,例如进程中的一个函数执行结束。堆栈中的数据容易消失,所以不能函数的返回值不能是指向堆栈的内存地址。
    3. 在函数中创建字符串变量、结构体变量,数据存储在进程的数据空间中,存储在堆栈中的只是数据的内存地址。
    4. 每个进程的堆栈栈顶可以是相同的。我的操作系统在初始化进程时,之所以使用不同的堆栈栈顶,是因为我的操作系统没有开启虚拟内存地址,使用的是相同的内存空间。如果使用相同的堆栈栈顶,不同进程的堆栈会相互覆盖。
    5. fork的实现:
      1. 子进程复制父进程的进程表,但是要使用不同的LDT选择子。
      2. 子进程要复制父进程的数据空间,同时要修改子进程的LDT。
    求道之人,不问寒暑。
  • 相关阅读:
    指向指针的指针
    判断是否遵守某个协议
    oc继承,实现,分类
    oc中没有空指针错误
    oc方法
    指针
    Array.diff
    ATM机允许4位或6位密码,而密码只能包含4位或6位数字。 如果函数传递了一个有效的PIN字符串,返回true,否则返回false。
    替换字符串中的字符为“(” 或“)”
    python 异常处理
  • 原文地址:https://www.cnblogs.com/chuganghong/p/15053920.html
Copyright © 2011-2022 走看看