fork()函数可以创建一个新的进程,被称为子进程,子进程获得父进程数据空间,堆和栈的副本.父子进程不共享这些存储空间部分,共享正文段.
看下面一个实例:
运行后结果:
一切正常运行,但是如果我们重定向标准输出流之后:
可以看到printf输出了两次,原因是在fork()之前调用了一次printf一次,但当调用fork()时,该行数据还在缓冲区中(因为重定向之后为全缓冲),然后讲父进程数据空间复制到子进程中时,该缓冲区数据也被复制到子进程中,此时父进程和子进程各自有了带该行内容的缓冲区.当进程终止时,缓冲区内容被刷新写到文件中.
子进程和父进程之间的区别如下:
fork返回值不同(进程ID不同)
子进程不继承父进程设置的文件锁
子进程的未处理闹钟被清除.
子进程的未处理信号集设置为空集.
有时候实际用户ID的进程总数超过了系统限制,会导致fork()失败.
vfork()函数用于创建一个新进程,而该进程的目的是exec一个新程序.vfork()不会将父进程的地址空间完全复制到子进程中,另一个区别是,vfork()保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行,当子进程调用这两个函数中的任意一个时,父进程会恢复运行.(如果在调用这两个函数之前子进程依赖父进程的进一步动作会导致死锁.)
引用网上的一个说法:
为什么会有vfork,因为以前的fork 很傻, 它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子 霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec 或者exit 后,相 于儿子买了自己的房子了,这时候就相当于分家了。