5.fork和vfork

fork和vfork函数都是用于创建子进程的系统函数。

fork函数调用一次,返回两次。两次返回的返回值不同。

1)返回值等于0时,处于子进程空间。

理由:一个进程只会有一个父进程,所以子进程总是可以调用getppid()来获得父进程的进程ID(进程ID为0的进程为系统的内核交换进程,所以一个子进程的进程ID不可能为0)

2)返回值为正值(也即子进程pid)时,处于父进程空间

理由:一个父进程可以创建多个子进程,并且也没有一个函数能够返回父进程的所有子进程ID。通过返回子进程的进程ID给父进程,有助于父进程记录子进程的相关信息。

 

fork()过程

父进程调用fork(),并从内存为此进程分配一个新的可用的进程标识符。之后,为这个进程分配进程空间,并将父进程进程空间中的数据段、堆栈段复制到子进程的进程空间之中。父子进程共享代码段,此时子进程和父进程一模一样。父子进程之间的执行顺序是不确定的,取决于内核的调度算法。由于子进程复制了父进程的堆栈段,因此两个进程都停留在了fork函数中,等待返回。因此fork函数调用一次,返回两次。


我们知道在调用fork()函数之后,常常会接着调用exec()函数。子进程会复制父进程的地址空间(数据段,堆栈),父子进程共享正文段(也即是代码段),尽管有写时复制技术,但是还是不可避免的会进行内存空间的复制。而后面我们要提到的vfork函数会直接使得子进程依附在父进程空间执行,只是子进程优先于父进程执行!


一般来说,fork之后父子进程之间的执行顺序是不确定的,取决于内核的调度算法。

fork函数与I/O函数之间具有一定的交互关系。比如在fork子进程之前,我们调用write函数输出一行内容,由于write函数是不带缓冲的,所以将其数据写到标准输出一次。标准I/O是带有缓冲的。我们知道,当标准输出连接到终端设备的时候,它是行缓冲的,其它的则是全缓冲的。由于标准输出缓冲区是以换行符来冲洗,因此当我们以交互式的方式运行该程序的时候。只得到该printf输出一次。而当我们将标准输出重定向到一个文件的时候,却可以得到两次输出行。其原因是子进程复制了父进程的数据空间,该缓冲区也被复制进子进程中,此时父子进程都拥有该行内容的缓冲区。具体看APUE(184)


记得,父进程的标准输出被重定向之后,子进程的标准输出也会被重定向的。很简单,其实fork的一个特性就是:父进程所有打开的文件描述符都会被复制到子进程之中。父子进程之间共享一个文件表项。

fork之后,处理文件描述符有两种情况:

1)父进程等待子进程完成。子进程读写操作完之后,更新文件描述符的文件偏移量。

2)父子进程各自执行不同的代码段。父子进程各自关闭自己不需要的文件描述符,这样就不会对对方产生影响。网络服务器程序就是这种处理方式。


fork一般有两种用法:

1)一个父进程希望复制自己,使父进程和子进程执行不同的代码段。例如:在服务器程序中,父进程用于监听外来连接,一旦请求介入,父进程就fork出子进程处理连接。

2)各自执行不同的程序。这在这种情况下,fork返回后立即调用exec函数。


vfork和fork的调用序列、返回值都是相同的。只是,vfork函数用于创建一个子进程,而这个子进程的目的是来exec一个新的程序。vfork创建的子进程在调用exec或者exit之前都在父进程空间执行。能够大大提高UNIX系统的实现效率。

vfork和fork另一个区别就是:vfork优先执行子进程!!!在它调用exec或者exit之后父进程才可能被调用。

但有一点缺点,如果子进程调用这两个函数的操作依赖于父进程的进一步操作,则会导致死锁的发生!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值