原文地址:http://hi.baidu.com/ikaruga11/blog/item/fb6d75725a8d8d148701b080.html
APUE上的一个例子:

example1 (forkt.c ):

#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>

int glob = 5;

int main()
{
        int var=10;
        pid_t pid;

printf("befork vfork\n");
        if((pid = fork()) < 0){
                printf("error\n");
                exit(1);
        }else if(pid == 0){
                glob++;
                var++;
                _exit(0);
        }
        printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
        exit(0);
}

执行
./forkt.c
./forkt.c > temp.out
将分别输出什么呢?

为了找出为什么会输出如上内容,以及fork vfork exit _exit的区别,于是改造上面的代码
example2:(省略了其他同上相同的代码)

printf("befork vfork\n");
        if((pid = fork()) < 0){
                printf("error\n");
                exit(1);
        }else if(pid == 0){
                glob++;
                var++;
                exit(0);
        }
        printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
        _exit(0);
执行
./forkt.c
./forkt.c > temp.out
将分别输出什么呢?

example3:(省略了其他同上相同的代码)

printf("befork vfork\n");
        if((pid = vfork()) < 0){
                printf("error\n");
                exit(1);
        }else if(pid == 0){
                glob++;
                var++;
                _exit(0);
        }
        printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
        exit(0);

执行
./forkt.c
./forkt.c > temp.out
将分别输出什么呢?

example4:(省略了其他同上相同的代码)

printf("befork vfork\n");
        if((pid = vfork()) < 0){
                printf("error\n");
                exit(1);
        }else if(pid == 0){
                glob++;
                var++;
                exit(0);
        }
        printf("pid = %d, glob = %d, var = %d",getpid(), glob,var);
        _exit(0);

./forkt.c
./forkt.c > temp.out
将分别输出什么呢?

先把几个概念缕一缕:
   fork: 子进程拥有父进程的数据段、堆和栈的副本,父进程和子进程共享正文段。但现在很多实现却并不是将父进程的数据段、堆栈段进行完全拷贝,而是采用写时复制(copy-on-write),内核将其标记为只读,(典型的页式虚存)只有父进程或子进程对这些区域进行修改时内核才真正将那一页进行拷贝,从物理上分离开。
   vfork:由于在vfork后经常是跟着一个exec执行一个新的程序不会在用到原来的地址空间,所以vfork的子进程在调用exec或exit之前是在父进程的空间里运行的,这样对于页式虚存效率很高。另外,vfork的子进程总是先与父进程执行,但是子进程不能依赖与父进程的执行否则产生死锁。

exit(0):根据实现的不同而不同,一般是刷新I/O缓冲区,关闭所有I/O标准流(APUE上如是说,但是我在linux下验证的结果应该是没有关闭),一般现在的I/O库函数在关闭I/O流方面不自找麻烦了。

_exit(0):不刷新I/O缓冲区

标准I/O库:
标准I/O库是带缓存的,如果标准输出是连接到终端设备,则它是行缓冲的,否则是全缓冲的。行缓冲在接收到一个换行符才进行刷新,而全缓冲在缓冲区满或者程序在执行exit退出后在执行缓冲区刷新

好了 ,现在我们来看看上面的例子到底输出什么东东了

example1:

执行:./forkt.c
交互方式执行,则是行缓冲, befork vfork后跟一个换行符\n,则刷新缓冲区输出 befork vfork,然后fork一个子进程,父子进程分别运行在不同的存储空间,子进程执行_exit()退出,不刷新缓冲区,父进程执行最后一个printf,但由于没有遇到\n,所以并不立即输出,在执行exit(0)后刷新缓冲区,此时输出
pid =6724, glob = 5, var =10

执行:./forkt.c > temp.out
非交互方式,则是全缓冲,首先执行printf("befork vfork\n")此时并不输出,而是缓存在缓冲区,然后fork一个子进程,父子进程分别运行在不同的存储空间,拷贝一份父进程中缓冲区的befork vfork\n 到子进程,子进程执行_exit()退出,不刷新缓冲区,父进程执行最后一个printf,也缓存起来并不立即输出,在执行exit(0)后刷新缓冲区,此时输出全部输出
cat > temp.out 输出如下:
befork vfork
pid =6731, glob = 5, var =10

example2:

执行:./forkt.c
交互方式执行,则是行缓冲, befork vfork后跟一个换行符\n,则刷新缓冲区输出 befork vfork,然后fork一个子进程,父子进程分别运行在不同的存储空间,子进程执行exit()刷新缓冲区退出,父进程执行最后一个 printf,但由于没有遇到\n,所以并不立即输出,在执行_exit(0)后由于不刷新缓冲区而退出,所以最后一个printf内容并不输出。所以
执行:./forkt.c
befork vfork

执行:./forkt.c > temp.out
非交互方式,则是全缓冲,首先执行printf("befork vfork\n")此时并不输出,而是缓存在缓冲区,然后fork一个子进程,父子进程分别运行在不同的存储空间,同时拷贝一份父进程中缓冲区的befork vfork\n 到子进程,子进程执行exit()刷新缓冲区退出,此时输出befork vfork\n ,父进程执行最后一个printf,也缓存起来并不立即输出,在执行_exit(0)后由于不刷新缓冲区而退出,因此输出
cat > temp.out 输出如下:
befork vfork

example3:

执行:./forkt.c
交互方式执行,则是行缓冲, befork vfork后跟一个换行符\n,则刷新缓冲区输出 befork vfork,然后vfork一个子进程,父子进程运行在相同的存储空间,子进程执行_exit()不刷新缓冲区退出,父进程执行最后一个 printf,但由于没有遇到\n,所以并不立即输出,在执行exit(0)后刷新缓冲区而退出,所以最后一个printf内容输出。所以
执行:./forkt.c
befork vfork
pid =6802, glob = 6, var =11

执行:./forkt.c > temp.out
非交互方式,则是全缓冲,首先执行printf("befork vfork\n")此时并不输出,而是缓存在缓冲区,然后vfork一个子进程,父子进程运行在相同的存储空间,子进程执行_exit()不刷新缓冲区退出,父进程执行最后一个printf,也缓存起来并不立即输出,在执行exit(0)刷新缓冲区而退出,因此输出
cat > temp.out 输出如下:
befork vfork
pid =6808, glob = 6, var =11

example4:
执行:./forkt.c
befork vfork
pid =6802, glob = 6, var =11

执行:./forkt.c > temp.out

cat > temp.out 输出如下:
befork vfork
pid =6808, glob = 6, var =11

另外

简单的说,exit函数将终止调用进程。在退出程序之前,所有文件关闭,缓冲输出内容将刷新定义,并调用所有已刷新的“出口函数”(由atexit定义)。
_exit:该函数是由Posix定义的,不会运行exit handler和signal handler,在UNIX系统中不会flush标准I/O流。
简单的说,_exit终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数。
共同:
不管进程是如何终止的,内核都会关闭进程打开的所有file descriptors,释放进程使用的memory!
note:
在由‘fork()’创建的子进程分支里,正常情况下使用‘exit()’是不正确的,这是 因为使用它会导致标准输入输出的缓冲区被清空两次,而且临时文件被出乎意料的删除(译者注:临时文件由tmpfile函数创建在系统临时目录下,文件名由系统随机生成)。
在C++程序中情况会更糟,因为静态目标(static objects)的析构函数(destructors)可以被错误地执行。
还有一些特殊情况,比如守护程序,它们的父进程需要调用‘_exit()’而不是子进程;适用于绝大多数情况的基本规则是,‘exit()’在每一次进入‘main’函数后只调用一次。

在由‘vfork()’创建的子进程分支里,‘exit()’的使用将更加危险,因为它将影响 父进程的状态

转载于:https://www.cnblogs.com/Myhsg/archive/2009/09/07/1562080.html

fork vfork exit _exit (转)相关推荐

  1. 【Linux进程、线程、任务调度】二 fork/vfork与写时拷贝 线程的本质 托孤 进程睡眠和等待队列

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2(已满): 780902027 学习 ...

  2. 6.exit _exit _Exit

    进程的终止有8种方式,5种正常终止和3中异常终止 5种正常终止: 1:从 main 执行return返回. 2:调用 exit(int x), 程序返回码是x,调用各种中止处理程序,关闭或冲洗缓冲区. ...

  3. 函数fork vfork

    一.函数fork fork函数原型: #include <unistd.h> pid_t fork(void); 二.程序清单 1. 测试代码: #include <unistd.h ...

  4. linux execl函数 errno,过程控制 Linux C fork() execl() exit() wait()

    进程控制 Linux C fork() execl() exit() wait() 进程控制实验: 在linux下面使用c语言利用系统调用fork(), execl(), exit(), wait() ...

  5. exit(),_exit()的区别

    Linux的源码 #define __NR_exit                 1 #define __NR__exit __NR_exit /* 摘自文件include/asm-i386/un ...

  6. fork,vfork以及exec的意义

    linux中创建进程是直接的,就是简单的一个fork调用,linux认为进程就是执行的一个任务,并没有和可执行文件联系起来,如果非要和可执行文件 联系的话就要涉及到另一个系统调用exec.linux这 ...

  7. C语言 exit() _exit()

    基础 在main中终断自己,并返回 1.0:sucess;1:failure;2:error _exit(int status); exit(int status); _Exit(int status ...

  8. exit() _exit()

    图 C程序的启动与终止 区别: _exit()函数:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构; exit()函 数则在这些基础上作了一些包装,在执行退出之前加了若干道工 ...

  9. 北理工操作系统实验合集 | API解读与例子

    文章目录 传送门 实验报告与源码下载 前言 进程控制API Linux getpid/getppid fork/vfork exit/_exit exec函数族 wait/waitpid pause/ ...

最新文章

  1. ubuntu 安装php-redis
  2. Spring.NET性能
  3. ACM第一天研究懂的AC代码——BFS问题解答——习题zoj2165
  4. 浅谈数据结构-平衡二叉树
  5. linux ftp图片服务器,linux ftp 图片服务器
  6. UVA - 11437 Triangle Fun(简单几何)
  7. BZOJ1876 [SDOI2009]SuperGCD 【高精 + GCD优化】
  8. C语言课后习题(15)
  9. 浅析C++开发工程师的高薪就业方向
  10. 防止浏览器嗅探音视频--blob对象在audio和video标签中的使用
  11. 教妹学Java:数组打印最优雅的方式deepToString
  12. FS FT DTFT DFT关系及频谱分析总结
  13. 菜鸟教程python3 mysql_MySQL菜鸟教程
  14. 如何调节MAC 命令行终端字体大小
  15. mysqli mysql assoc_mysqli_fetch_assoc()期望参数1为mysqli_result或如何获取MySQLi
  16. word中如何制作三线表
  17. web怎么将dwg转换图片_怎么将DWG图纸转换成JPG格式图片
  18. css3的nth为什么不生效,CSS:nth-​​child(偶数)选择器背景颜色不起作用
  19. PNG怎么转换成PDF?这篇文章教会你
  20. Oracle数据库-第三章:单值函数

热门文章

  1. python web开发 jQuery基础
  2. 牛客 String II
  3. 词云(WordCloud)制作
  4. LeetCode 1063. 有效子数组的数目(单调栈)
  5. LeetCode 1085. 最小元素各数位之和
  6. LeetCode 421. 数组中两个数的最大异或值(Trie树)
  7. 向量空间 Vector Space -- 推荐系统
  8. Java基础10(反射)
  9. linux强制停止压缩任务,6.25任务(linux压缩、打包命令:zip、tar)
  10. ios13全选手势_iOS13系统5个简单实用的技巧 快速选择/三指操作/批量删除短信/文字转表情...