功能:创建一个新的进程
头文件#include <unistd>
原型:pid_t fork(void);
返回值:成功返回0或>0的数
失败返回-1
备注:函数执行成功后将会产生一个新的子进程,在新的子进程中返回0,在原来父进程中返回大于0的整数,该整数就是子进程的PID
例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t x;
x=fork();
if(x>0)//父进程
{
printf("[%d]:parent\n",(int)getpid());
exit(0);
}
if(x==0)//子进程
{
printf("[%d]:child\n",(int)getpid());
exit(0);
}
}
内核有意选择子进程首先执行。因为一般子进程都会马上调用exec()函数,这样可以避免写时拷贝的额外开销,如果父进程首先执行的话,有可能会开始向地址空间写入。
进阶知识:
传统的fork()系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,因为它拷贝的数据也许并不共享,更槽的情况是,如果新进程打算立即执行一个新的映像,那么所有的拷贝都将前功尽弃。Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。
只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候才进行。在页根本不会被写入的情况下(举例来说,fork()后立即调用exec())它们就无须复制了。
fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。在一般情况下,进程创建后都会马上运行一个可执行的文件,这种优化可以避免拷贝大量根本就不会被使用的数据(地址空间里常常包含数十兆的数据)。