简体   繁体   中英

what is the difference between _exit function and return statement in linux

Consider the following code:

#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;
}

the result as follow: ppid = 21297,pid = 21553,g_a = 2,l_b = 2

but when i replace the _exit(0); with return 0;, the result became:

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

Segmentation fault

there is a segmentation faut,what is the difference between _exit and return??

Returning from main is equivalent to calling exit , which does a bunch of cleanup operations (such as flushing open FILE objects and running atexit procedures) and then calls _exit , which is the system call that actually terminates a process. So when you call _exit directly, you skip all of those cleanup operations.

You are using vfork . It is incorrect (formally, it "provokes undefined behavior") to do anything on the child side of a vfork except call _exit or execve . Returning from main counts as doing something else (namely, calling exit ). It is not at all surprising, therefore, that your program crashes.

EDIT: As far as the relevant specifications are concerned, modifying the variables g_a and l_b on the child side of the vfork is also forbidden, in the same dire terms ("undefined behavior" in the strong sense, ie "allowed to cause your program to crash"). However, in all extant implementations I am aware of, catastrophe only strikes if the child does anything to cause memory (including stack frames) to be allocated or deallocated. Modifying variables that were allocated by the parent, but visible to the child (whether local or global) is unpredictable in a much more bounded manner:

  1. If vfork is just another name for fork , nothing the child does will be visible in the parent;
  2. But if vfork has its special behavior of delaying allocation of the new address space until execve , then modifications by the child to variables resident in memory will be visible in the parent after the parent resumes execution. (Variables resident in registers may or may not get reset when the kernel restores the parent's execution context, depending on how full a context switch that does.)

And, if you know your OS is type 2, you can get away with using this to your advantage, eg to pass errno back to the parent after execve fails, which is significantly harder with plain fork (because the exit status is too narrow). It is, however, something you are getting away with rather than something you are entitled to do; in particular it is a source of future portability headaches.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM