美文网首页LinuxLinux学习之路
APUE读书笔记-07进程环境(1)

APUE读书笔记-07进程环境(1)

作者: QuietHeart | 来源:发表于2020-05-08 12:00 被阅读0次

    1、简介

    在下一章讲述进程控制相关的内容之前,我们需要先看一下单个进程的情况。本章,我们将会看到 main 函数在执行程序的时候是如何被调用到的,命令行参数是如何传递给新的程序的,典型的内存布局是什么样的,以及如何申请额外的内存,进程如何使用环境变量,以及各种终止进程的方法。另外,我们也会看到 longjmp 函数和 setjmp 函数,以及它们和堆栈的交互情况。最后我们通过讲述一个进程的资源限制来结束本章。

    译者注

    原文参考

    参考: APUE2/ch07lev1sec1.html

    2、可执行程序的 main 函数

    当一个c程序通过 exec 被执行的时候,会在 main 函数之前首先调用一个 start-up routine .根据编译时候链接阶段的设置,可执行文件会把这个 start-up routine 作为程序的起始地址。这个 start-up routine 会从内核中获取命令参数(应该对应 main 函数的参数)以及环境变量然后调用 main 函数。

    main 函数的声明如下:

    int main(int argc, char *argv[]);
    

    这里,参数 argc 是命令行中参数的数目, argv 是指向命令行参数的数组。这个函数的内容是我们自己实现的,依据我们自己的程序功能而有所不同。例如假设 mytest.c 编译生成 mytest 程序,那么输入 mytest arg1 arg2 之后, mytest.c 中的 main 函数的 argc 就是3,其中 argv[0]mytestargv[1]arg1argv[2]arg2 。具体我们会在7.4中对这些参数进行讲述。

    译者注

    原文参考

    参考: APUE2/ch07lev1sec2.html

    3、进程终止

    有8种结束进程的方式,其中:

    (1)正常结束的方式有5种:

    • main 函数中 return
    • 调用 exit 函数
    • 调用 _exit = 或者 =_Exit
    • 最后一个线程中的 start routinereturn
    • 从最后一个线程中调用 pthread_exit .

    (2)非正常结束的方式有3种:

    • 调用 abort .
    • 接收到一个信号( signal ).
    • 响应最后一个线程的 cancellation 请求。

    这里,我们只考虑和线程无关的方法。

    main 函数 return 的时候会调用到 exit 函数。效果类似在前面提到的 start-up routine 中执行了 exit(main(argc,argv));

    实际真正正常结束程序的只有三个函数: exit , _exit_Exit .

    _exit_Exit 会直接立即返回到内核,而 exit 会首先做一些清理工作(例如关闭打开的 stream )然后返回到内核(例如可通过调用其他的两个 exit 函数)。

    三种 exit 声明如下:

    #include <stdlib.h>
    void exit(int status);
    void _Exit(int status);
    
    #include <unistd.h>
    void _exit(int status);
    

    这三种函数都返回一个整数表示进程的状态,大多数unix系统都有处理这个返回状态的方式。

    如果

    • 这三种函数没有指定 status 而被调用
    • main 函数调用了 return 却没有在后面指定其返回值
    • main 函数没有指定要返回一个整数进程的 exit 状态是不确定的。

    如果 main 函数被指定返回的是整数,但是是隐式退出的(没有调用 return 而是自然地到达了函数的结尾),那么返回值是0(这个特性是 c99 新加的特性,以前返回是不确定的)。在 main 函数中调用 exit(0)return 0 的效果是等价的。

    进程结束前可以调用用户注册的指定函数:

    #include <stdlib.h>
    int atexit(void (*func)(void));
    

    我们把自己定义的函数的地址传递到这个函数中去,就会将我们自定的函数注册到进程退出过程中去。当调用 exit 函数退出进程的时候,会按照我们注册的反顺序一次调用我们注册的自定义函数。一个函数被注册了几次,那么 exit 的时候就会被调用几次。 ISO C 允许注册至少 32 个函数( sysconf 函数可以用来确定一个系统最多可以注册多少个退出函数)。

    这些退出函数( exit 注册的函数)在 1989 ANSI 之前的系统中(例如 SVR34.3BSD )是没有的。

    ISO CPOSIX.1 首先调用注册的 exit 退出函数,然后(通过 fclose )关闭所有的 stream.POSIX.1 扩展了 ISO C 的一个地方是:当调用 exec 函数的时候会清除所有的退出注册函数。下图给出了程序启动和终止时候调用的这些函数的关系。

                                                   C程序的启动和终止
    
        _exit+---------------------------------------------------------------------+
         or  |                                                                     |
        _Exit|  +----------+                                call    +-------+      |
      <---------|  user    |                             ---------->|  exit |      |
      |      |  |functions |\                           /  /--------|handler|      |
      |      |  +--|----^--+ \   exit                  /  /  return +-------+      |
      |      |  return  |     -------------\          /  /                         |
      |      |     |    |   (doesn't return)\        /  /            ......        |
      | _exit|     |  call                   v      /  /                           |
      |  or  |  +--v----|--+     exit       +--------+<    call     +-------+      |
      | _Exit|  |  main    |--------------->|  exit  |------------->|  exit |      |
      | <-------|functions |(doesn't return)|function|<-------------|handler|      |
      | |    |  +--|----^--+                +----|---+\    return   +-------+      |
      | |    |  return  |                    ^   |  ^  \                           |
      | |    |     |    |                   /    |   \  \                          |
      | |    |     |  call       exit      /     |    \  \                         |
      | |    |  +--v----|--+  ------------/      |     \  \  call   +-----------+  |
      | |    |  |C start-up| /(doesn't return)   |_exit \  \------->| standard  |  |
      | |    |  |  routine |/                    | or    \----------|I/O cleanup|  |
      | |    |  +-----^----+                     |_Exit      return +-----------+  |
      | |    |        |                          |                                 |
      | |    +--------|--------------------------|---------------------------------+
      | |             |                          |
      | |             |exec                      |
      v v             |                          |
    +-----------------|--------------------------v------------------------------------------+
    |                                    kernel                                             |
    +---------------------------------------------------------------------------------------+
    

    总结起来,程序大致退出的情况是:

    1. 用户函数最终会返回到main
    2. main返回到start-routine
    3. start-routine最后会调用exit函数;
    4. main函数和用户函数都能够调用exit或_exit或_Exit直接退出程序;
    5. exit最终会调用_exit或_Exit退出程序。

    译者注

    原文参考

    参考: APUE2/ch07lev1sec3.html

    相关文章

      网友评论

        本文标题:APUE读书笔记-07进程环境(1)

        本文链接:https://www.haomeiwen.com/subject/azddghtx.html