fork函数是非常重要的函数,它的作用是从已经存在的进程中创建一个子进程,而原进程称为父进程。
函数原型:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
失败的两个主要原因是: 1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。 2)系统内存不足,这时 errno 的值被设置为 ENOMEM。
实例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
//注意:执行了fork函数就会在原有进程上创建一个子进程,而fork之后不区分父子进程代码区。后面所有的代码都会执行。
fork();
printf("hello,world!");
while(1){
}
return 0;
}
测试运行:
hello,world!
hello,world!
注意:window下没有一个函数可以实现UNIX下的fork()函数,其原因是历史造成的.对于UNIX来说它一出生就是多用户的系统,所以它的所有进程都共有一个最原始的父进程init.而windows生下来时是个单用户系统(DOS),不存在这样的概念.所以fork这个函数是UNIX下特有的。因此以上代码也只能在linux环境下运行。
我们通过fork函数的返回值来区分父子进程的代码块。 实例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int pid = fork();
if (pid < 0)
{
perror("erro to create process:");
}
if (pid > 0)
{
//这里是父进程代码块
while (1)
{
printf("I am father pid=%d,ppid=%d\n",getpid(),getppid());
printf("I am father!\n");
printf("pid = %d\n",pid);
sleep(1);
}
}
else
{
//这里是子进程代码块
while (1)
{
printf("I am son pid=%d,ppid=%d\n",getpid(),getppid());
printf("I am son!\n");
sleep(1);
}
}
return 0;
}
测试运行:
[root@iz2zefozq9h39txdb8s7npz shelldemo]# ./a.out
I am father pid=13535,ppid=13023
I am father!
pid=13536
I am son pid=13536,ppid=13535
I am son!
I am father pid=13535,ppid=13023
I am son pid=13536,ppid=13535
I am father!
pid=13536
注意:这里父子进程是按照时间片交替执行,并不是父进程执行完之后执行子进程。一般来说,在 fork() 之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。
使用 fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信息)。因此,使用 fork() 函数的代价是很大的。

简单来说,一个进程调用 fork() 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
为验证父子进程各自的地址空间是独立的,看下面实例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int a = 100; // 全局变量
int main(int argc, char *argv[])
{
int b = 200; //局部变量
static int c = 300; //静态变量
int pid;
pid = fork();
if (pid < 0)
{
//没有创建成功
perror("error to create process:");
}
if (pid > 0)
{
//父子进程
a++;
b++;
c++;
printf("father: a = %d, b = %d, c=%d\n", a, b, c);
}
else
{
//子进程
sleep(1); // 保证父进程先运行,但不保证1秒足够
printf("son: a = %d, b = %d,c=%d\n", a, b, c);
}
while(1){
}
return 0;
}
测试运行:
[root@iz2zefozq9h39txdb8s7npz shelldemo]# ./a.out
father: a = 101, b = 201, c=301
son: a = 100, b = 200,c=300