学习fork函数,首先要了解进程的含义。
csapp上说:进程是计算机科学中最深刻、最成功的概念之一。进程的经典定义就是一个执行中的程序的实例。系统中的每个程序都运行在某个进程的上下文(context)中。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
每次用户通过向shell输入一个可执行目标文件的名字,运行程序时,shell就会创建一个新的进程,然后在这个新的进程的上下文中运行这个可执行目标文件。应用程序也能够创建新进程,并且在这个新进程的上下文中运行他们自己的代码或其它应用程序。
父进程通过调用fork函数创建一个新的运行的子进程。新创建的子进程几乎但不完全与父进程相同。子进程得到与父进程用户级虚拟地址空间相同的(但独立的)一份副本,包括代码和数据段、堆、共享库以及用户栈。子进程还获得与父进程中打开文件描述符相同的副本,这就意味着当父进程调用fork时,子进程可以读写父进程中打开的任何文件。父进程和新创建的子进程之间最大的区别在于他们有不同的PID。
fork函数只被调用一次,却会返回两次:一次是在父进程中,一次是子进程中。在父进程中,fork返回子进程的PID。在子进程中,fork返回0。因为子进程的PID总是为非零,返回值就提供一个明确的方法来分辨程序是在父进程还是在子进程中执行。
简而言之,fork的四个特点分别是:调用一次,返回两次;并发执行;相同但是独立的地址空间;共享文件。
接下来先查看一下18种不同的fork:
/*
* forks.c - Examples of Unix process control
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/*
* fork0 - The simplest fork example
* Call once, return twice
* Creates child that is identical to parent
* Returns 0 to child process
* Returns child PID to parent process
Hello from parent
Hello from child
*/
void fork0()
{
if (fork() == 0) {
printf("Hello from child\n");
}
else {
printf("Hello from parent\n");
}
}
/*
* fork1 - Simple fork example
* Parent and child both run same code
* Child starts with identical private state
Parent has x = 0
Bye from process 2629 with x = 0
Child has x = 2
Bye from process 2630 with x = 2
*/
void fork1()
{
int x = 1;
pid_t pid = fork();
if (pid == 0) {
printf("Child has x = %d\n", ++x);
}
else {
printf("Parent has x = %d\n", --x);
}
printf("Bye from process %d with x = %d\n", getpid(), x);
}
/*
* fork2 - Two consecutive forks
* Both parent and child can continue forking
* Ordering undetermined
L0
L1
Bye
$ Bye
L1
Bye
Bye
*/
void fork2()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("Bye\n");
}
/*
* fork3 - Three consective forks
* Parent and child can continue forking
L0
L1
L2
Bye
$ Bye
L2
Bye
L1
L2
Bye
Bye
Bye
L2
Bye
Bye
*/
void fork3()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("L2\n");
fork();
printf("Bye\n");
}
/*
* fork4 - Nested forks in parents
L0
L1
L2
Bye
$ Bye
Bye
*/
void fork4()
{
printf("L0\n");
if (fork() != 0) {
printf("L1\n");
if (fork() != 0) {
printf("L2\n");
}
}
printf("Bye\n");
}
/*
* fork5 - Nested forks in children
L0
Bye
$ L1
Bye
L2
Bye
*/
void fork5()
{
printf("L0\n");
if (fork() == 0) {
printf("L1\n");
if (fork() == 0) {
printf("L2\n");
}
}
printf("Bye\n");
}
void cleanup(