Linux 进程:C fork() 函数
程序的每个运行实例都称为进程。进程的概念是Linux 操作系统的基础。进程有自己的身份,以 PID 或进程 ID 的形式存在。每个进程的这个 PID 在整个操作系统中都是唯一的。此外,每个进程都有自己的进程地址空间,其中放置了代码段、数据段、堆栈段等内存段。流程的概念非常广泛,大致可以分为流程创建、流程执行和流程终止。
在本文中,我们将从编程的角度专注于流程创建方面。我们将专注于 fork() 函数并了解它是如何工作的。
fork() 函数
fork() 函数用于通过复制调用它的现有进程来创建新进程。调用此函数的现有进程成为父进程,新创建的进程成为子进程。如前所述,孩子是父母的副本,但也有一些例外。
- 与操作系统中运行的任何其他进程一样,子进程具有唯一的 PID。
- 子进程的父进程 ID 与创建它的进程的 PID 相同。
- 资源利用率和 CPU 时间计数器在子进程中重置为零。
- child 中的未决信号集为空。
- 子级不从其父级继承任何计时器
请注意,上面的列表并不详尽。fork() 的手册页中提到了很多要点。我强烈建议本文的读者仔细阅读 fork() 函数手册页中的这些要点。
返回类型
Fork() 在返回调用方法时有一个有趣的行为。如果 fork() 函数成功,则返回两次。一旦它以返回值“0”在子进程中返回,然后它以子进程的 PID 作为返回值在父进程中返回。这种行为是因为一旦调用了 fork,就会创建子进程,并且由于子进程与父进程共享文本段并从同一文本段中的下一条语句继续执行,因此 fork 返回两次(一次在父进程中)和孩子一次)。
C 分叉示例
下面举个例子来说明fork函数的使用。
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int var_glb; /* A global variable*/
int main(void)
{
pid_t childPID;
int var_lcl = 0;
childPID = fork();
if(childPID >= 0) // fork was successful
{
if(childPID == 0) // child process
{
var_lcl++;
var_glb++;
printf("\n Child Process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb);
}
else //Parent process
{
var_lcl = 10;
var_glb = 20;
printf("\n Parent process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb);
}
}
else // fork failed
{
printf("\n Fork failed, quitting!!!!!!\n");
return 1;
}
return 0;
}
在上面的代码中:
- 用值 '0' 声明和初始化的局部变量和全局变量(var_lcl 和 var_glb)
- 接下来调用 fork() 函数并将其返回值保存在变量 childPID 中。
- 现在,检查 childPID 的值以确保 fork() 函数通过。
- 接下来根据 childPID 的值,执行 parent 和 child 的代码。
- 这里要注意的一件事是为什么要使用变量 var_lcl 和 var_glb?
- 它们用于表明子进程和父进程都在这些变量的单独副本上工作。
- 这些变量的单独值用于显示上述事实。
- 在 linux 中,使用了一种写时复制机制——在子节点和父节点中,他们一直在处理同一个变量副本,直到其中一个尝试更改其值。
- fork 之后,child 先运行还是 parent 运行取决于调度器。
现在,当上面的代码编译并运行时:
$ ./fork
Parent process :: var_lcl = [10], var_glb[20]
Child Process :: var_lcl = [1], var_glb[1]
我们在上面的输出中看到,子进程和父进程都被执行,并且日志显示了 var_lcl 和 var_glb 的不同值。由此得出结论,父母和孩子都有自己的 var_lcl 和 var_glb 副本。
注意:函数 getpid() 可用于获取调用进程的进程 ID,函数 getppid() 可用于获取父进程的 PID。
- 点赞
- 收藏
- 关注作者
评论(0)