LinuxLinux学习之路

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

2020-05-08  本文已影响0人  QuietHeart

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种:

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

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

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系统都有处理这个返回状态的方式。

如果

如果 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

上一篇下一篇

猜你喜欢

热点阅读