进程,进程和线程的区别


原文链接:http://www.orlion.ga/1015/

一、进程

    每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,linux内核的进程控制块是task_struct结构体,其中有:

  • 进程id。系统中每个进程有一个唯一的id,在C语言中用pid_t类型表示,是一个非负正是

  • 进程的状态,有运行、挂起、停止、僵尸等状态

  • 进程切换时需要保存和恢复的一些CPU寄存器

  • 描述虚拟地址空间的信息

  • 描述控制终端的信息

  • 当前工作目录

  • umask掩码

  • 文件描述符表,包含很多指向file结构体的指针

  • 和信号相关的信息

  • 用户id和组

  • 控制终端、Session和进程组。

  • 进程可以使用的资源上限

 

    fork的作用是根据一个现有的进程(父进程)复制出一个新进程(子进程),系统中同时运行着多个进程,这些进程都是从最初只有一个进程开始一个一个复制出来的,在Shell下输入命令可以运行一个程序,是因为Shell进程在读取用户输入的命令之后会调用fork复制出一个新的Shell进程,然后新Shell进程调用exec执行新的程序。

    一个程序可以多次加载到内存中成为同时运行的多个进程,例如可以同时开多个终端运行/bin/bash。一个进程在调用exec前后也可以分别执行两个不同的程序,例如在Shell下输入命令ls,首先fork创建子进程,这时子进程仍在执行/bin/bash程序然后子进程调用exec执行新的程序/bin/ls。如下图所示:

    

    子进程的PCB是根据父进程复制而来的,所以其中的umask掩码也和父进程一样。同样道理子进程的当前工作目录也和父进程一样,所以我们用cd改变Shell进程的工作目录,然后ls列出那个目录下的文件,ls进程其实是在列自己的当前目录,而不是Shell进程的当前目录,只不过ls进程的目录和Shell的目录一样。但是子进程PCB中的进程id和父进程不同。

    

二、环境变量

 

    exec系统调用执行新程序时会把命令行参数和环境变量表传递给main函数,它们在整个进程地址空间中的位置如下所示:

    

    和命令行参数argv类似,环境变量表也是一组字符串,如下图所示:

    

    libc定义的全局变量environ指向环境变量表,environ没有包含在头文件中,所以在使用时要用extern声明。例:

#include <stdio.h>

int main(void)
{
    extern char **environ;
    int i;
    for (i=0; environ[i] != NULL; i++)
        printf("%s\n", environ[i]);
    
    return 0;
}

    执行结果为:

    

    由于父进程在调用fork创建子进程时会把自己的环境变量表也复制给子进程,所以打印的环境变量和Shell进程打印的环境变量是相同的。环境变量定义了进程的运行环境。

    可以用char *getenv(const char *name)获取name在环境变量表中对应的value。

    可以用int setenv(const char *name, const char *value, int rewrite);设置环境变量。

    可以用void unsetenv(const char *name);删除name的定义。

    在子进程中修改环境变量并不会改变父进程的环境变量。

相关内容

    暂无相关文章