1、fork函数的定义
头文件:
#
include
#
include
函数原型:
pid_t fork(
void);
(pid_t 是一个
宏定义,其实质是int 被定义在#
include<
sys/types.h>中)
返回值: 若成功调用一次则返回两个值,子进程返回0,
父进程返回子进程ID;否则,出错返回-1
函数说明:
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述
存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
UNIX将复制父进程的
地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。
2、函数特点和进阶
从上面的函数说明里面可以看到fork函数会有几个特点:
(1)返回两个值不同的值代表不同的意思。
(2)子进程获得父进程的数据空间和堆栈等资源并且独立的。
举个简单的例子如下:
#include
#include
int main()
{
pid_t fpid;//fpid表示fork函数返回的值
fpid = fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0)
printf("I am the child process, my process id is %d\n", getpid());
else
printf("I am the parent process, my process id is %d\n", getpid());
return 0;
}
这个例子最中的结果为:
I am the parent process, my process id is 11594
I am the child process, my process id is 11595
可以明显看出来个不同进程的不同打印出来了,具体打印什么要看linux系统的调度算法了。main函数在fork之后变成了两个进程。可以各自干各自的事情。
第二个例子:
int main()
{
pid_t fpid;//fpid表示fork函数返回的值
printf("fork!");
fpid = fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0)
printf("I am the child process, my process id is %d\n", getpid());
else
printf("I am the parent process, my process id is %d\n", getpid());
return 0;
}
这个例子比第一个例子多了一个printf(fork!");
这个例子的输出结果为:
fork!I am the parent process, my process id is 11852
fork!I am the child process, my process id is 11853
上面的例子你会看到一个现象:子进程继承了父进程的数据空间,导致子进程和父进程都输出了fork!。但是如下如果加上\n
#include
#include
int main()
{
pid_t fpid;//fpid表示fork函数返回的值
printf("fork!\n");
fpid = fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0)
printf("I am the child process, my process id is %d\n", getpid());
else
printf("I am the parent process, my process id is %d\n", getpid());
return 0;
}
输出结果:
fork!
I am the parent process, my process id is 11950
I am the child process, my process id is 11951
此时结果只有一个fork!打印了,这是为什么呢?这是因为prinf的行数据缓冲问题,在没有加\n的时候数据是在缓冲区中,没有直接输出到stdout,当加上\n的时候数据会刷新输出到stdout。所以出现了上面的情况。
再列举一个简单的例子:
#include
#include
int main ()
{
pid_t fpid; //fpid表示fork函数返回的值
int count=0;
fpid=fork();
if (fpid < 0)
printf("error in fork!\n");
else if (fpid == 0) {
printf("i am the child process, my process id is %d\n",getpid());
printf("child\n");
count++;
}
else {
printf("i am the parent process, my process id is %d\n",getpid());
printf("parent\n");
count++;
}
printf("%s, %d, %d\n", __FUNCTION__, __LINE__,count);
return 0;
}
输出结果为:
i am the parent process, my process id is 12163
parent
main, 92, 1
i am the child process, my process id is 12164
child
main, 92, 1
这个例子清晰的看到count是子进程从父进程获取到的独立的栈数据,在输出的时候分别都是1,而不是2。
3、
fork出错可能有两种原因:
1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
2)系统内存不足,这时errno的值被设置为ENOMEM。
上述简单介绍fork函数的用法,后续继续讲解fork和vfork函数的区别。