您的位置:首页 > 其它

关于fork与vfork,exit与_exit

2012-02-21 15:30 489 查看
fork和vfork都是创建进程,exit和_exit都是退出进程,但之间也有些细微的区别,并且很让人迷惑。一般情况下用fork创建的子进程用exit结束,而用vfork创建的进程则用_exit。那他们具体的区别在哪儿了,为什么这么做!

预备知识:程序的存储空间布局,系统的缓冲区

c程序在内存中从高地址到低地址依次为:

命令行参数和环境变量:存储命令行的各个参数和系统的环境变量

栈段:局部变量(函数内部定义使用的变量)和函数调用存放的位置,此块由操作系统处理

堆段:通常在堆里面进行动态存储分配,malloc就是分配堆里面的空间,通常由程序员控制

数据段:存储一些初始化数据和非初始化数据

正文段:cpu执行的机器码

系统的缓冲区:

操作系统为了提高文件都写效率,都使用的缓存机制,当我们写入一个文件时,很有可能写入了缓冲区而没有真真意义上的写入硬盘,缓存分为三个级别:

全缓冲:当缓冲空间(4096B或其它)写满后,一次性写入硬盘,文件缓存通常如此

行缓冲:遇到输入输出遇到换行符,执行写入操作,命令行界面就是使用行缓冲

无缓冲:这个就不用解释了

fork与vfork

执行fork创建子进程时,子进程将拷贝父进程的数据段、堆段和栈段,此时父子进程的数据一致当互相独立,各不影响,子进程对数据的处理不影响父进程。(其实当父子进程都不对三个段进行写操作时,父子进程仍然共享数据段、堆段和栈段,当有任何一方有写操作时,才产生副本,这种方式成为写是复制)

vfork与fork区别有两点:1、vfork创建的子进程与父进程共享数据段,2、vfork创建的子进程优先于父进程执行,当子进程执行时,父进程进入阻塞状态。

所以vfork产生的子进程对数据的修改一定可以影响到父进程的数据

exit与_exit

exit:当执行exit时,终止处理程序,执行标准的I/O清楚操作(将缓存中文件写入),调用atexit,调用_exit。由此可见,exit是加强版的_exit.

_exit:通知内核,进程结束

测试exit和_exit

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

int main(void)
{
printf("the first line\n");

printf("the second line\n");

exit(0);
}


eno@eno-ThinkPad-T420:~$ vim exit.c
eno@eno-ThinkPad-T420:~$ gcc exit.c -o exit
eno@eno-ThinkPad-T420:~$ ./exit
the first line
the second line
eno@eno-ThinkPad-T420:~$

结果与预期相同,改为_exit(0)

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

int main(void)
{
printf("the first line\n");

printf("the second line\n");

_exit(0);
}


eno@eno-ThinkPad-T420:~$ ./_exit
the first line
the second line
eno@eno-ThinkPad-T420:~$

结果怎么还是一样的,有的系统可能看到是没有输出,这都是正常的,每个系统最输出的缓存机制可能不一致,通常为行缓存,把他强制设置成全缓存看看:

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

int main(void)
{
char buf[4096];
//设置成全缓存
setvbuf(stdout, buf, _IOFBF, 4096);

printf("the frist line\n");

printf("the second line\n");

_exit(0);
}

ok,结果与预期相同,缓冲区的数据全部没掉了

eno@eno-ThinkPad-T420:~$ gcc _exit.c  -o _exit
eno@eno-ThinkPad-T420:~$ ./_exit
eno@eno-ThinkPad-T420:~$

这么一比划,就基本上明白了为什么fork产生的子进程要用exit而不用_exit了,如果缓冲区的东西都丢了,子进程所产生的数据就不完整,这对于程序使用者来说是不可接受的。那为什么vfork一般用_exit了,难道不怕丢数据么?用vfork的子程序通常用_exit结束,而父进程通常用exit结束,这样做数据就不会丢失,因为他们共享一个数据段,父进程结束会处理所有打开的数据流,将其写入。万一子程序也用exit结束,那就比较麻烦了,试想一下父子进程都把同一份数据写入,那个文件的价值有在哪里。
本文出自 “邱凯的技术博客” 博客,请务必保留此出处http://xdebug.blog.51cto.com/1135229/785763
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: