运行程序是一个 过程。从这个过程中,可以创建另一个过程。这两个进程之间存在父子关系。这可以使用名为 fork() 的库函数来实现。 fork()函数将正在运行的进程拆分为两个进程,现有进程称为父进程,新进程称为子进程。这是一个演示这一点的程序:
C
// C program to demonstrate
// the above concept
#include
#include
#include
// Driver code
int main()
{
printf ("Before Forking\n");
fork();
printf ("After Forking\n");
}
C
// C program for the above approach
#include
// Driver Code
int main( )
{
int pid;
pid = fork();
if (pid == 0)
{
printf ("In child process\n");
/* code to play animated GIF file */
}
else
{
printf ("In parent process\n");
/* code to copy file */
}
}
C
// C program to implement
// the above approach
# include
// Driver code
int main()
{
int pid;
pid = fork();
if (pid == 0)
{
printf ("Child : I am the child process\n");
printf ("Child : Child’s PID: %d\n", getpid());
printf ("Child : Parent’s PID: %d\n", getppid());
}
else
{
printf ("Parent : I am the parent process\n");
printf ("Parent : Parent’s PID: %d\n", getpid());
printf ("Parent : Child’s PID: %d\n", pid);
}
}
Before Forking
After Forking
Before Forking
After Forking
说明: fork()之后的所有语句都执行了两次:
- 一旦通过父进程。
- 第二次语句由子进程执行。
让我们更详细地讨论以下概念:
- 过程。
- 父进程。
- 子进程。
进程:进程是正在执行的程序,即活动程序。进程不仅仅是程序代码,它还包括以下内容:
- 程序计数器。
- 进程栈。
- 寄存器。
- 程序代码等
相反,程序代码只是一个文本部分。
进程在执行时会更改其状态。新状态部分取决于进程的当前活动。进程在执行过程中的不同状态是:
- 新的
- 准备好
- 跑步
- 被封锁
- 终止。
进程控制块和进程表与每个进程相关联。它包含有关该过程的以下重要信息:
- 进程状态。
- 进程号。
- 程序计数器。
- 文件和寄存器列表。
- CPU信息。
- 内存信息等
父进程:除启动进程外,所有进程都是在进程执行 fork() 系统调用时创建的。执行的过程 fork() 系统调用是父进程。父进程是使用 fork() 系统调用创建子进程的进程。一个父进程可以有多个子进程,但一个子进程只有一个父进程。
在 fork() 系统调用成功时:
- 子进程的进程 ID (PID) 返回给父进程。
- 0 返回给子进程。
在 fork() 系统调用失败时,
- -1 返回给父进程。
- 未创建子进程。
子进程:子进程由操作系统中的父进程使用 fork() 系统调用创建。子进程也可以称为子进程或子任务。
- 创建子进程作为其父进程的副本。
- 子进程继承了它的大部分属性。
- 如果子进程没有父进程,则子进程由内核直接创建。
- 如果子进程退出或被中断,则向父进程发送 SIGCHLD 信号以通知子进程终止或退出。
为什么我们需要创建子进程?
有时需要一个程序同时执行多个函数。由于这些作业可能相互关联,因此无法创建两个不同的程序来执行它们。例如:假设有两个作业:将源文件的内容复制到目标文件,并显示一个动画进度条,指示文件复制正在进行中。 GIF 进度条文件应继续播放,直到文件复制发生。复制过程完成后,应停止播放 GIF 进度条文件。由于这两项工作相互关联,因此不能在两个不同的程序中执行。此外,它们不能一个接一个地执行。两项工作应同时进行。
在这种情况下, fork()用于创建一个子进程,然后以这样一种方式编写程序,即文件复制由父进程完成,动画 GIF 文件的显示由子进程完成。
程序 1:这里的任务是展示如何同时执行两个不同但相互关联的工作。因此,文件复制和播放动画 GIF 文件的实际代码已被跳过,仅显示了同时执行 2 个作业的方法。
C
// C program for the above approach
#include
// Driver Code
int main( )
{
int pid;
pid = fork();
if (pid == 0)
{
printf ("In child process\n");
/* code to play animated GIF file */
}
else
{
printf ("In parent process\n");
/* code to copy file */
}
}
说明: fork()创建子进程,在子进程中复制父进程的代码。之后 fork()函数在两个进程中继续执行。因此,fork() 中的重复代码执行一次,而其中剩余的代码在父进程和子进程中都执行。因此,即使实际上只调用了一次,控制权也会从 fork() 返回两次。当控制从父进程的 fork() 返回时,它返回子进程的 PID,而当控制从子进程的 fork() 返回时,它总是返回 0。这可以被程序利用来隔离我们希望在父进程中执行的代码来自我们希望在子进程中执行的代码。这个逻辑是在上面的程序中使用 if 语句实现的。在“如果块”在子进程的情况下执行,“else块”在父进程的情况下执行。
方案二:
该程序将使用fork()调用来创建子进程。在子过程中,我们将打印的孩子和其母公司的PID,而在父进程中,我们将打印父的PID和它的孩子。
C
// C program to implement
// the above approach
# include
// Driver code
int main()
{
int pid;
pid = fork();
if (pid == 0)
{
printf ("Child : I am the child process\n");
printf ("Child : Child’s PID: %d\n", getpid());
printf ("Child : Parent’s PID: %d\n", getppid());
}
else
{
printf ("Parent : I am the parent process\n");
printf ("Parent : Parent’s PID: %d\n", getpid());
printf ("Parent : Child’s PID: %d\n", pid);
}
}
输出:
Child : I am the child process
Child : Child's PID: 4706
Child : Parent's PID: 4705
Parent : I am the Parent process
Parent : Parent's PID: 4705
Parent : Child's PID: 4706