UNIX程序设计中fork和vfork,exit和_exit的区别

创建子进程有很多种方式,调用fork()vfork()是其中的两种方式

就说说forkvfork的不同之处吧。

fork:

父进程调用完fork成功以后创建一个子进程,而且这个子进程会拷贝一份父进程的数据空间,堆和栈空间。并且父子进程的内存空间是完全独立的,并不共享。父进程和子进程谁先执行是不确定的。

vfork:

父进程调用完vfork后同样创建一个子进程,但是不同之处在于,子进程会先运行,在遇到exec或exit之后父进程才能运行(也就是说子进程结束以后父进程才能运行),子进程没有拷贝一份父进程的地址空间,而是在父进程的地址空间中运行。

下面来个例子吧。

fork:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
        pid_t   pid;
        int     value;

        value = 10;
        pid = fork();
        if (pid < 0)
        {
                perror("fork failed!\n");
                exit(0);
        }
        else if( pid == 0 )//child
        {
                value++;
        }
        else
        {
                waitpid(pid,NULL,0);
                printf("value = %d\n", value);
        }
        return 0;
}
$ ./ a.out
value = 10

vfork:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
        pid_t   pid;
        int     value;

        value = 10;
        pid = vfork();
        if (pid < 0)
        {
                perror("fork failed!\n");
                exit(0);
        }
        else if( pid == 0 )//child
        {
                value++;
                _exit(0);
        }
        else
        {
                printf("value = %d\n", value);
        }
        return 0;                                                                                                                                                                              ~                 

$ ./a.out

value = 11


很明显两次打印的结果不同了,可以看出fork后的父子是不共享内存空间的,而vfork后子进程是在父进程地址空间运行的,共用内存空间的。

大家可能看得了我在第二个程序的子进程中用了_exit(0)来退出进程而不是用常用的exit(0)来退出。下面就来讲下exit和_exit的区别。

当调用exit(0)以后,系统会清洗缓冲区,并且关闭全部的标准I/O流。而调用_exit(0)后缓冲区冲不冲洗得看具体实现,在UNIX系统中,是不清洗的。

一个简单的例子:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
        int     value;

        value = 1;
        printf("%d",value);
        _exit(0);
}

$ ./a.out

$

什么也没有输出来

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
        int     value;

        value = 1;
        printf("%d",value);
        exit(0);
}
$ ./a.out

1$

这里输出1了

由于printf是行缓冲的,行满了或遇到换行符\n时才会将缓冲区数据打印出来,当调用exit(0)时,系统会在结束前将缓冲区的内容都冲洗出来,所以就打印出来了,而调用_exit(0)并不一定会冲洗缓冲区(冲不冲洗得看具体系统实现),所以就可能不打印出来了。

为什么要把exit,_exit和fork,vfork一块讲呢?看下面代码


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
        pid_t   pid;
        int     value;

        value = 10;
        pid = vfork();
        if (pid < 0)
        {
                perror("fork failed!\n");
                exit(0);
        }
        else if( pid == 0 )//child
        {
                value++;
                exit(0);//将刚才的_exit改成exit
        }
        else
        {
                printf("value = %d\n", value);
        }
        return 0;
}

上面将刚才的 _exit(0)改成exit(0)

可能会出现的情况是父进程打印不出东西来(具体还是得看系统实现),因为vfork后的子进程和父进程在同一个地址空间中运行,子进程调用会exit(0)会关闭标准输入输出流,所有会导致父进程的输出流被子进程关闭了,导致输出不了,(可能有些系统还是可以输出,因为系统实现不同,但是还是不要用exit()比较好)。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值