C编程语言中的Fork()
如果你使用的是Windows,你可能已经在你的任务管理器中看到了很多的进程。如果你使用的是Linux,则在你的资源监视器中。你有没有停下来想一想,这些进程是如何产生的?
在本教程中,我们将讨论fork() 函数,然后用C语言编程实现一些例子。
前提条件
要跟上本教程,你应该具备以下条件。
- 对C编程语言有良好的理解。
- 对类Unix操作系统有一定的了解。
什么是进程?
进程是一个计算机程序的实例,由一个或多个线程执行。它包含程序代码和它的活动。根据操作系统(OS)的不同,一个进程可能是由多个执行线程组成的,它们同时执行指令。
什么是Fork()?
在计算机领域。 **fork()**是类Unix操作系统上创建进程的主要方法。这个函数从原始进程中创建一个新的副本,称为子进程,这个子进程被称为父进程。当父进程关闭或因某种原因崩溃时,它也会杀死子进程。
让我们从一个进程的生命周期开始。

操作系统正在为每个进程使用一个唯一的ID来跟踪所有进程。为此,fork() ,不接受任何参数,并返回一个int值,如下。
- 零:如果它是子进程(创建的进程)。
- 正值:如果它是父进程。
- 负值:如果发生错误。
注意:下面的代码只在基于Linux和UNIX的操作系统中运行。如果你运行的是Windows,那么我建议你使用[Cygwin]。
让我们跳到实践部分,我们将创建从简单水平到高级水平的例子。
Hello world!
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
/* fork a process */
fork();
/* the child and parent will execute every line of code after the fork (each separately)*/
printf("Hello world!\n");
return 0;
}
输出将是。
Hello world!
Hello world!
其中一个输出来自父进程,另一个来自子进程。

简单地说,我们可以知道结果是n的2次方,其中n是fork()系统调用的数量。
比如说。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
fork();
fork();
fork();
printf("Hello world!\n");
return 0;
}
其结果是:
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
另一个例子是:
int main() {
if(fork() == 0)
if(fork())
printf("Hello world!!\n");
exit(0);
}
我画了一个简单的草图来帮助你理解这个想法。

在第一个if 条件中,发生了一个fork,它正在检查它是否是子进程,然后继续执行它的代码。否则(如果是父进程),它将不会通过该if 。然后,在第二个if ,它将只接受持有正ID的父进程。
结果,它将只打印一个 "Hello world!"。
现在试着执行下面的代码,并将你的结果与我们的比较。
int doWork(){
fork();
fork();
printf("Hello world!\n");
}
int main() {
doWork();
printf("Hello world!\n");
exit(0);
}
其结果将是。
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!

因为当被分叉在dowork() 内的进程打印出Hello World! ,它将在函数调用后继续主代码,并打印出Hello World! ,然后退出。
高级例子
当一个进程创建一个新的进程时,那么执行退出有两种可能。
- 父进程继续与子进程同时执行。
- 父进程等待,直到它的一些或所有的子进程都终止了。
#include <sys/types.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
/* fork a child process */
pid_t pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
printf("I'm the child \n"); /* you can execute some commands here */
}
else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
/* When the child is ended, then the parent will continue to execute its code */
printf("Child Complete \n");
}
}
等待调用系统wait(NULL) ,将使父进程等待,直到子进程执行完其所有的命令。
其结果将是。
I'm the child
Child Complete
另一个例子。
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("I am: %d\n", (int) getpid());
pid_t pid = fork();
printf("fork returned: %d\n", (int) pid);
if (pid < 0) { /* error occurred */
perror("Fork failed");
}
if (pid == 0) { /* child process */
printf("I am the child with pid %d\n", (int) getpid());
printf("Child process is exiting\n");
exit(0);
}
/* parent process */
printf("I am the parent waiting for the child process to end\n");
wait(NULL);
printf("parent process is exiting\n");
return(0);
}
结果将是这样的。
I am: 2337
fork returned: 2338
I am the parent waiting for the child process to end
fork returned: 0
I am the child with pid 2338
Child process is exiting
parent process is exiting
今天就到此为止!🥳
总结
我们已经了解了fork()的作用,以及如何在C语言中用独特的例子实现它。如果你对操作系统的抽象感兴趣,以及它是如何工作的,那么我建议你开始学习管道和信号灯的知识。