当前位置:嗨网首页>书籍在线阅读

02-进程的终止__exit()和exit()

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

25.1 进程的终止:_exit()和exit()

通常,进程有两种终止方式。其一为异常(abnormal)终止,如20.1节所述,由对一信号的接收而引发,该信号的默认动作为终止当前进程,可能产生核心转储(core dump)。此外,进程可使用_exit()系统调用正常(normally)终止。

660.png _exit()的status参数定义了进程的终止状态(termination status),父进程可调用wait()以获取该状态。虽然将其定义为int类型,但仅有低8位可为父进程所用。按照惯例,终止状态为0表示进程“功成身退”,而非0值则表示进程因异常而退出。对非0返回值的解释则并无定例;不同的应用程序自成一派,并会在文档中加以描述。SUSv3规定有两个常量:EXIT_SUCCESS(0)和EXIT_FAILURE(1),本书中大部分程序就采用了这一约定。

调用_exit()的程序总会成功终止(即,_exit()从不返回)。

虽然可将0~255之间的任意值赋给_exit()的status参数,并传递给父进程,不过如取值大于128将在shell脚本中引发混乱。原因在于,当以信号(signal)终止一命令时,shell 会将变量$?置为 128 与信号值之和,以表征这一事实。如果这与进程调用_exit()时所使用的相同status值混杂起来,将令shell无法区分。

程序一般不会直接调用_exit(),而是调用库函数 exit(),它会在调用_exit()前执行各种动作。

661.png exit()会执行的动作如下。

  • 调用退出处理程序(通过 atexit()和 on_exit()注册的函数),其执行顺序与注册顺序相反(见25.3节)。
  • 刷新stdio流缓冲区。
  • 使用由status提供的值执行_exit()系统调用。

与专属于UNIX的_exit()不同,exit()则属于标准C语言函数库,也就是说,所有的C语言实现都支持exit()。

程序的另一种终止方法是从 main()函数中返回(return),或者或明或暗地一直执行到main()函数的结尾处。执行return n等同于执行对exit(n)的调用,因为调用 main()的运行时函数会将 main()的返回值作为 exit()的参数。

存在一种情况,从main()函数中返回与调用exit()并不相同。如果在退出的处理过程中所执行的任何步骤需要访问main()函数的本地变量,那么从main()函数中返回会导致未定义的行为。例如,在调用setvbuf()或setbuff()(见13.2节)时引用了main函数的本地变量,就会发生这种情况。

执行未指定返回值的return,或是无声无息地执行到main()函数结尾,同样会导致main()的调用者执行 exit()函数,不过,视所支持的不同C语言标准版本,以及所使用的不同编译器选项,其结果也有所不同。

  • C89 标准未就上述情况下的行为进行定义,程序可以返回任意的 status 值。Linux gcc 的默认行为就是如此,程序的退出状态是取自于栈或特定CPU寄存器中的随机值。应避免以这一方式终止程序。
  • C99 标准则要求,执行至 main 函数结尾处的情况应等同于调用 exit(0)。如果使用gcc–std=c99在Linux中编译程序,将会获得这种效果。