Linux 系统中调用 exit() 和 _exit() 结束进程的区别

根据此图,进程终止方式有三种(不涉及多线程情况下),分别为:

  1. 进程调用_exit或_Exit(两者等价),进程立即终止,内核负责各项清理工作,如移除进程表项(自然也包括“关闭”进程的文件描述符),发送SIGCHILD信号给父进程等。
  2. 进程调用exit函数,exit逐一调用进程事先通过atexit或onexit注册的exit handler,然后清理stdio,最后调用_exit。
  3. 从main函数return,然后start-up例程(在main函数之前执行的代码,与操作系统有关,会完成为进程提供环境变量/命令行参数等工作)调用exit函数。
    不难看出,exit相比于_exit/_Exit,就是多做了两件事:
  4. 调用用户通过atexit/on_exit注册的exit handler,要了解这部分内容可以参考这atexit/on_exit两个函数的手册。
  5. 清理stdio,即通过fclose,关闭stdin,stdout,stderr。

exit多做的两件事中,第一件很好理解,带来的区别也很容易感受到,所以我们接下来看看exit多做的第二件事,即清理stdio,会带来什么影响。
首先我们要知道,stdio的一大作用,就是为输入输出提供缓冲,尽量减少系统调用(read/write)的次数。而一旦涉及到缓冲,就不得不提出一个问题:如何缓冲?
stdio提供了三种缓冲形式:

  1. 无缓冲。这种模式下,每一次调用getchar/gets等标准输入函数都会调用read,每一次调用putchar/puts等标准输出函数都会调用write。好处是不用担心缓冲带来的各类问题,比如子进程与父进程对同一内容的两次输出,缓冲区内容丢失等;坏处是系统调用次数多,容易降低程序性能。
  2. 行缓冲。这种模式下,标准输入输出函数会在遇到换行符时,才进行真正的I/O:putchar('a')只是将'a'放入stdout的缓冲区,再接一个putchar('\n'),才会令'a'和'\n'真正被输出。当然,缓冲区如果满了,也会导致真正的I/O发生。fgets的行为也是行缓存式行为(哪怕stdin不是行缓冲)。
  3. 全缓冲。这种模式下,标准输入输出函数仅在缓冲区满了的情况下,才会进行真正的I/O。
    对于Linux来说,stdio所选的默认缓冲形式一般为:
  4. stderr无缓冲。
  5. 如果stdin/stdout指向终端,则为行缓冲,否则为全缓冲。
    知道stdio存在缓冲与缓冲形式后,我们要知道,清理stdio,即通过fclose关闭stdin/stdout/stderr时,fclose会对stdout/stderr调用fflush,将其缓冲区剩余数据输出到目标文件(或设备)中。
    最后,我们就能明白exit多做的第二件事,会带来怎样的区别了:如果stdout/stderr缓冲区中还有数据,那么exit会将这些数据输出到文件(或设备)中,而_exit则不会,从而导致缓冲区数据被抛弃。

我们可以通过一个简单的程序来测试一下上述说法是否正确:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    printf("abcd"); //注意,没有换行
    _exit(0);
}

nspt@linux:~$ gcc test.c 
nspt@linux:~$ ./a.out 
nspt@linux:~$

程序没有输出"abcd",这个不难理解,因为此时stdout指向终端,为行缓冲,而我们调用printf所输出的字符串没有换行(也没有填满缓冲区),所以"abcd"留在了缓冲区,_exit又没有清理stdio,所以缓冲区中的"abcd"也就随着进程终止,被清理掉了(而不是输出到目标)。

如果我们将_exit替换为exit,那么"abcd"就会输出到终端:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    printf("abcd");
    exit(0);
}

nspt@linux:~$ gcc test.c
nspt@linux:~$ ./a.out
abcdnspt@linux:~$

最后,我们来看看子进程调用exit与调用_exit的区别。

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

int main()
{
    printf("abcd");
    if (fork()==0)
        exit(0); //Child exit
    sleep(2); //Wait child
    exit(0);
}

nspt@linux:~$ gcc test.c
nspt@linux:~$ ./a.out
abcdabcdnspt@linux:~$
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇