曲径通幽论坛

标题: fork -- 创建新进程 [打印本页]

作者: beyes    时间: 2009-5-29 23:14
标题: fork -- 创建新进程
在 linux 中创建一个新进程的惟一方法是使用 fork() 函数。fork()函数执行一次返回两个值

函数原型
pid_t fork(void);

所需头文件

#include <sys/types.h>    /*提供类型 pid_t 的定义*/
#include <unistd.h>

函数返回值
-1: 出错
0 : 子进程
子进程 ID( 大于 0 的整数):父进程
函数说明
fork() 从已存在的进程中创建一个新进程。新进程称为子进程,而原进程成为父进程。这两个分别带回它们各自的返回值,其中父进程的返回值是子进程的进程号,而子进程则返回 0 。因此,可以通过返回值来判定该进程是父进程还是子进程。

使用 fork 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文,进程堆栈,内存信息,打开的文件描述符,进程控制设定,进程优先级,进程组号,当前工作目录,根目录,资源限制,控制终端等。子进程所独有的只是有它的进程号、资源使用和计时器等。因此可以看出,使用 fork() 函数的代价是很大的,它复制了父进程中的代码段、数据段和堆栈段里的大部分内容,使得 fork() 函数的执行速度并不很快。

如果 fork() 失败了(返回 -1),通常是因为受到最大允许子进程数目的限制(CHILD_MAX),这里 errno 会被标志为 EAGAIN。如果是因为进程表(process table) 里没有足够的空间开辟出一个登记入口,或者是因为没有足够的虚拟内存,则 errno 变量被置为 ENOMEN

使用 fork() 函数的典型片段
pid_t new_pid;

new_pid = fork();

switch(new_pid) {
    case -1:         /* Error */
        break;
    case 0:         /* We are child */
        break;
    default:         /* We are parent */
        break;
}
测试代码
一般情况下的运行及输出
beyes@linux-beyes:~/C/call/fork> ./fork2.exe
fork program starting
This is the parent
This is the child
This is the parent
This is the child
This is the parent
This is the child
This is the child
beyes@linux-beyes:~/C/call/fork> This is the child
多次尝试运行次程序也会出现不同的输出结果
beyes@linux-beyes:~/C/call/fork> ./fork2.exe
fork program starting
This is the parent
This is the child
This is the parent
This is the child
This is the child
This is the parent
This is the child
beyes@linux-beyes:~/C/call/fork> This is the child
说明
不同的输出结果是因为系统调度对进程调度的原因。分析第一个输出的流程:首先执行 fork() 后创建了一个新的进程,但此时由于系统的调度原因,当前进程还是处于父进程空间中,所以输出“
This is the parent“;接着执行了 sleep() 函数后,父进程睡眠,系统调度子进程运行,然后子进程输出“This is the child”,此后交替反复。如上面所说,子进程复制了父进程的上下文,所以父进程有父进程的 n 值(输出“This is the parent”3次),子进程也有子进程的 n 值( 输出"This is the child" 5次)。    

Tip:
由于 fork() 完整地拷贝了父进程的整个地址空间,因此执行速度是比较慢的。为了加快 fork() 的执行速度,有些 UNIX 系统设计者创建了 vfork() 。vfork() 也能创建新进程,但它不产生父进程的副本。它是通过允许父子进程可访问相同物理空间内存从而伪装了对进程地址空间的真实拷贝,当子进程需要改变内存中的数据时才拷贝父进程。这就是著名的“写操作时拷贝“( copy-on-wirte)技术。

现在很多嵌入式 Linux 系统的 fork() 函数调用都采用 vfork() 函数的实现方式,实际上 uClinux 所有的多进程管理都通过 vfork() 来实现。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2