linux中的_exit函数和return语句有什么区别

时间:2013-11-14 03:09:42

标签: c

请考虑以下代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int g_a = 1;

int main(void){
    int l_b = 1;
    pid_t p;
    if((p = vfork()) < 0){
            perror("vfork");
            return -1;
    }else if(p == 0){
            g_a++;
            l_b++;
            _exit(0);   //use the system call _exit
    }
    printf("ppid = %d,pid = %d,g_a = %d,l_b = %d\n", getppid(), getpid(), g_a, l_b);
    return 0;
}

结果如下:     ppid = 21297,pid = 21553,g_a = 2,l_b = 2

但当我替换_exit(0);返回0;,结果变为:

ppid = 21297,pid = 21563,g_a = 2,l_b = -1216841009

分段错误

有一个分段问题,_exit和return之间有什么区别?

1 个答案:

答案 0 :(得分:4)

main返回等同于调用exit,它执行一系列清理操作(例如刷新打开的FILE对象并运行atexit过程)然后调用_exit,这是实际终止进程的系统调用。因此,当您直接调用_exit时,您将跳过所有这些清理操作。

您正在使用vfork。除了调用vforkexecve之外,在_exit的子方面执行任何是不正确的(正式地,它引起了未定义的行为)。从main返回算作做其他事情(即调用exit)。因此,程序崩溃并不奇怪。

编辑:就相关规范而言,修改g_a子侧的变量l_bvfork也是禁止的,用同样可怕的术语(强烈意义上的“未定义行为”,即“允许导致程序崩溃”)。 但是,在我所知道的所有现存实现中,只有当子进行任何事情导致内存(包括堆栈帧)被分配或释放时,灾难才会发生。修改由父级分配但对子级可见的变量(无论是本地的还是全局的)变量是不可预测的:

  1. 如果vfork只是fork的另一个名称,那么孩子所做的一切都不会在父母身上看到;
  2. 但是如果vfork具有延迟分配新地址空间直到execve的特殊行为,那么子对内存中驻留的变量的修改将在父节点恢复执行后的父节点。 (驻留在寄存器中的变量可能会或可能不会在内核恢复父执行上下文时重置,具体取决于上下文切换的完整程度。)
  3. 而且,如果您知道您的操作系统是类型2,那么您可以使用此功能,例如在errno失败后将execve传递回父级,这对于普通fork来说要困难得多(因为退出状态太窄)。然而,这是你逃避的事情,而不是你有权做的事情;特别是它是未来可携带性问题的根源。