fork 函数由父进程调用,在失败时返回 -1 给父进程。在 pipeUN 这个例子中,相应的调用是:
pid_t cpid = fork(); /* called in parent */
函数调用后的返回值也被保存下来了。在这个例子中,保存在整数类型 pid_t 的变量 cpid 中。(每个进程有它自己的进程 ID,这是一个非负的整数,用来标记进程)。复刻一个新的进程可能会因为多种原因而失败,包括进程表满了的原因,这个结构由系统维持,以此来追踪进程状态。明确地说,僵尸进程假如没有被处理掉,将可能引起进程表被填满的错误。
假如 fork 调用成功,则它将创建一个新的子进程,向父进程返回一个值,向子进程返回另外的一个值。在调用 fork 后父进程和子进程都将执行相同的代码。(子进程继承了到此为止父进程中声明的所有变量的拷贝),特别地,一次成功的 fork 调用将返回如下的东西:
在一次成功的 fork 调用后,一个 if /else 或等价的结构将会被用来隔离针对父进程和子进程的代码。在这个例子中,相应的声明为:
if (0 == cpid) { /*** child ***/ ... } else { /*** parent ***/ ... }
假如成功地复刻出了一个子进程,pipeUN 程序将像下面这样去执行。在一个整数的数列里:
int pipeFDs[2]; /* two file descriptors */
来保存两个文件描述符,一个用来向管道中写入,另一个从管道中写入。(数组元素 pipeFDs[0] 是读端的文件描述符,元素 pipeFDs[1] 是写端的文件描述符。)在调用 fork 之前,对系统 pipe 函数的成功调用,将立刻使得这个数组获得两个文件描述符:
if (pipe(pipeFDs) < 0) report_and_exit("pipeFD");
父进程和子进程现在都有了文件描述符的副本。但分离关注点模式意味着每个进程恰好只需要一个描述符。在这个例子中,父进程负责写入,而子进程负责读取,尽管这样的角色分配可以反过来。在 if 子句中的第一个语句将用于关闭管道的读端:
close(pipeFDs[WriteEnd]); /* called in child code */
(编辑:ASP站长网)
|