linux下通过fork方式创建的子进程,通常在子进程中通过调用exit系统函数来退出。

exit函数会执行子进程数据和资源的清理操作,包括关闭从父进程继承的或自身创建的文件或socket句柄、管道、内存等资源,对于C++的全局变量,还会执行析构。

对于文件句柄等系统资源的释放,本身由操作系统自己完成,基本上不会涉及到应用层的代码,所以一般也不会引发异常。

因此对于C++程序来说,需要特别注意的就是全局对象析构时可能触发的异常。

为什么子程序会在析构全局对象时出现异常呢,一个主要的原因就是fork在复制父进程的内存镜像时,某些全局对象正在进行修改操作,处于一种不一致的状态

比如对于一个全局的std::string对象,正对它进行赋值操作,导致其正在调整内部buff缓存时进行了fork,这时子进程继承过来的string对象的内部缓存就可能指向了无效地址,

这样子进程析构这个string对象时就会崩溃。

因此linux下一个fork的使用原则就是多线程的程序慎用fork操作,或者一个例外就是fork后,立刻执行exec系统调用来接管子进程,且如果exec失败就调用_exit退出子进程

void main()
 {
    int rtn; /*子进程的返回数值*/
 
    if ( fork() == 0 ) {/* 子进程执行此命令 */
        execlp(“ls”,”ls”,”-al”,”/etc/passwd”,(char *)0);
        /* 如果exec函数返回,表明没有正常执行命令,退出子进程*/
        _exit( errno );
    }
    else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */
        wait ( &rtn );
        printf( " child process return %d\n", rtn );
    }
}



上面通过执行_exit 退出后,不会执行atexit注册的清理函数,所以也不会进行C++全局变量的析构,因此规避了前面提到的析构不完整对象的问题



关于_exit,有下面的说明:

void _exit(int status);

 DESCRIPTION
        The  function  _exit  terminates the calling process "immediately". Any open file descriptors belonging to
        the process are closed; any children of the process are inherited by process 1, init,  and  the  process's
        parent is sent a SIGCHLD signal.
以及exit和_exit的区别如下:
From POSIX programmers' guide


 Calling exit()
 The exit() function causes normal program termination. The EXIT_SUCCESS macro can
 be used to indicate successful termination. Since the POSIX standard requires that
 EXIT_SUCCESS be defined as zero, it is safe to write exit(0), keeping with historical
 practice. The call exit(0) is extremely portable.
 The exit() function performs the following functions:
 1. All functions registered by the Standard C atexit() function are called in the reverse
 order of registration. If any of these functions calls exit(), the results are not portable.
 2. All open output streams are flushed (data written out) and the streams are closed.
 3. All files created by tmpfile() are deleted.
 4. The _exit() function is called.

 Calling _exit()
 The _exit() function performs operating system-specific program termination functions.
 These include:
 1. All open file descriptors and directory streams are closed.
 2. If the parent process is executing a wait() or waitpid(), the parent wakes up and
 status is made available.
 3. If the parent is not executing a wait() or waitpid(), the status is saved for return to
 the parent on a subsequent wait() or waitpid().
 4. Children of the terminated process are assigned a new parent process ID. Note: the
 termination of a parent does not directly terminate its children.
 5. If the implementation supports the SIGCHLD signal, a SIGCHLD is sent to the parent.
 6. Several job control signals are sent.最后的建议:
 Portable programs should use exit() instead of _exit(). The _exit() function exists
 mainly because of the structure of traditional implementations and also the structure of
 standards committees. The exit() function is defined by the C standard with some features
 that are beyond the scope of POSIX. The only reason for an application to call _exit() is to
 defeat the flushing of streams and the calling of functions registered by atexit().