1、fork 函数原型:pid_t fork(void);
函数返回值类型为 pid_t,实质是 int 类型,Linux 内核2.4.0版本的定义是:
typedef int _kernel_pid_t;
typedef _kernel_pid_t pid_t;
2、fork 函数的底层实现:
fork()、vfork()和clone()的底层均调用do_fork(),只是传递参数和标志不同。该函数定义了一个task_struct类型的指针,用来接收即将为子进程所分配的进程描述符;使用alloc_pidmap()为子进程分配pid参数;调用copy_process()方法创建子进程的描述符,并创建子进程所需的其他数据结构。
3、fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。
fork 函数调用一次,返回两次:
(1)在父进程中返回子进程的 pid
(2)在子进程中返回0
失败则返回 -1。
4、fork 函数在生成子进程时,用到了写时拷贝技术。
写时拷贝:不执行一个父进程数据段、堆、栈的完全复制,这些区域由父、子进程共享,而内核将他们的访问权限改为只读的。当任意一个进程试图修改共享内存中的数据,则内核只为修改区域的那块内存制作一个副本,并且是以虚拟存储器系统中的“一页”为单位复制。
5、僵死进程:子进程先于父进程结束,父进程没有调用 wait 获取子进程的退出码,这时,子进程就变为僵死进程。
6. fork 相关习题:
(1)程序执行后,输出了3个A;
int main()
{
fork() || fork();
printf("A\n");
}
(2)程序执行后,输出了6个A;
int main()
{
int i = 0;
for( ; i<2; i++)
{
fork();
printf("A\n");
}
}
(3)程序执行后,输出了8个A;(注意,输出语句后没有“\n”,数据被暂时存在缓冲区,最后全部被打印)
int main()
{
int i = 0;
for( ; i<2; i++)
{
fork();
printf("A"); //注意 无“\n”
}
}