Skip to content

fork函数

1、简介

复刻(英语:fork,又译作派生、分支)是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

从一个软件包拷贝了一份源代码然后在其上进行独立的开发,创建不同的软件。这个术语不只意味着版本控制上的分支,同时也意味着开发者社区的分割,是一种形式的分裂。

自由及开放源代码软件可以从原有开发团队复刻而不需要事先的许可,这也不会违反任何著作权法律。授权的专有软件(例如Unix)的复刻也时有发生。

fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。

它不需要参数并返回一个整数值。下面是fork()返回的不同值。

  • 负值:创建子进程失败。
  • 零:返回到新创建的子进程。
  • 正值:返回父进程或调用者。该值是新创建的子进程的进程ID。

2、函数说明

一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。 子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。 UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。

fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。

2、fork与vfork的区别

fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别:

  • 1.fork():子进程拷贝父进程的数据段,代码段 vfork():子进程与父进程共享数据段
  • 2.fork()父子进程的执行次序不确定 vfork保证子进程先运行,在调用exec或exit之前与父进程数据是共享的,在它调用exec或exit之后父进程才可能被调度运行。
  • 3.vfork()保证子进程先运行,在她调用exec 或exit 之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

为什么会有vfork,因为以前的fork 很傻, 它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子霸占着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec 或者exit 后,相当于儿子买了自己的房子了,这时候就相当于分家了。

waitpid

waitpid会暂时停止目前进程的执行,直到有信号来到或子进程结束。

#include<sys/types.h>
#include<sys/wait.h>
定义函数 pid_t waitpid(pid_t pid,int * status,int options);

如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回 返回值-1。失败原因存于 errno 中。

This website is released under the MIT License.