Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 进程中的fork()、wait()和exit()功能_C_Unix_Operating System_Fork_Wait - Fatal编程技术网

C 进程中的fork()、wait()和exit()功能

C 进程中的fork()、wait()和exit()功能,c,unix,operating-system,fork,wait,C,Unix,Operating System,Fork,Wait,我有一个C源代码,如下所示 #include<stdio.h> #include<stdlib.h> #include<sys/wait.h> #include<unistd.h> #include<sys/types.h> int main(void) { pid_t process_id; int status; if (fork() == 0) { if (fork() == 0)

我有一个C源代码,如下所示

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
#include<sys/types.h>

int main(void) {

   pid_t process_id;
   int status;

   if (fork() == 0) 
   {
       if (fork() == 0)
       {
           printf("A");
       } else {
           process_id = wait(&status);
           printf("B");
       }
   } else {
       if (fork() == 0)
       {
           printf("C");
           exit(0);
       }
       printf("D");
   }
   printf("0");
   return 0;   
}
#包括
#包括
#包括
#包括
#包括
内部主(空){
进程id;
智力状态;
如果(fork()==0)
{
如果(fork()==0)
{
printf(“A”);
}否则{
进程id=等待(&状态);
printf(“B”);
}
}否则{
如果(fork()==0)
{
printf(“C”);
出口(0);
}
printf(“D”);
}
printf(“0”);
返回0;
}
当我在终端执行它时,我得到了一些输出,显示在这张图中:

实际上,我对这些输出是如何生成的感到困惑。例如,D0A0~$B0C是如何生成的

有谁能解释一下这些输出是如何生成的,以及
是否在此代码中退出(0)?

如果您有这样的代码,一般情况下

if (fork() == 0) {
  printf("I'm a child\n");
} else {
  printf("I'm a parent\n");
}

printf("This part is common\n");
然后,fork()结果为零的if分支将在子进程中执行,非零分支将在父进程中执行。在这之后,执行将在两个进程中继续(仍然是异步的),因此子进程和父进程都将在if之后执行代码。我们可以用下图来表示它,显示将在每个分支中执行的代码:

                                       fork()
                                      /    \
             ------- parent ----------      ---------- child -----------
             |                                                         |
             |                                                         |
   printf("I'm a parent\n");                          printf("I'm a child\n");
   printf("This part is common\n");                   printf("This part is common\n");
现在,让我们为您的代码制作相同的图表。在第一个fork之后,如果出现以下情况,则根据最顶层分割执行:

                                    fork()
                                   /    \
         --------- parent ---------      ---------- child -------------
         |                                                            |
         |                                                            |

      if (fork() == 0)                                 if (fork() == 0)
      {                                                {
        printf("C");                                      printf("A");
        exit(0);                                       } else {
      }                                                   process_id = wait(&status);
      printf("D");                                        printf("B");
                                                       }

      // Common code                                  // Common code
      printf("0");                                    printf("0");                
      return 0;                                       return 0;
在父级和子级中执行下一个fork之后,我们将得到以下树结构:

                                    fork()
                                   /    \
                ----  parent ------      ------ child ------
                |                                          |
              fork()                                     fork()
              /    \                                     /    \
--- parent ---      --- child ---          --- parent ---      --- child ----
|                               |          |                                 |
|                               |          |                                 |
printf("D");           printf("C");      process_id = wait(&status);      printf("A");
                       exit(0);          printf("B");
                       printf("D");

printf("0");           printf("0");      printf("0");                     printf("0");
return 0;              return 0;         return 0;                        return 0;
注意printf(“D”);出现在父-父分支和父-子分支中,因为它实际上是这两个分支中位于
if(fork()==0){}
之后的公共代码

此时,所有4个进程都在异步执行

  • 父进程打印“D”,然后打印“0”,然后退出

  • 父子进程打印“C”,然后退出

  • 子-父进程等待其子进程的完成,然后打印“B”,然后打印“0”并退出

  • 子进程打印“A”,然后打印“0”,然后退出

正如您所看到的,这些进程的输出几乎可以任意交错,唯一的保证是在子-父进程打印“B0”之前,子进程将打印“A0”。用于运行程序的shell将在主进程(即父进程)完成后获得控件。但是,当控件返回shell时,可能仍有其他进程在运行,因此在shell输出其命令提示符后,可能会出现某些进程的输出。例如,以下事件链是可能的:

  • 父控件获取控件。它打印“D0”并退出,控件返回shell

  • 子-父进程获取控件。它开始在子进程上等待(正在阻塞)

  • 子进程获取控件。它打印“A0”并退出

  • 同时,shell进程获取控件并打印命令提示符“~$”

  • 子-父进程获取控件。由于子进程已完成,它将被取消阻止,打印“B0”并退出

  • 父子进程获取控件,打印“C”并退出


组合输出为“D0A0~$B0C”。它解释了示例中的最后一行。

这里涉及四个过程,我们称它们为
a
b
c
,和
d
d
b
c
,而
b
a
的父级):

  • d
    是执行第一个
    fork(2)
    调用(创建进程
    b
    )的父进程。由于它是父级,它将转到第一个
    if
    else
    语句,并将
    再次fork(2)
    (创建进程
    c
    ),然后在末尾打印字符串
    D0
    (两个字符总是在一个
    write(2)
    调用中一起写入,如
    printf(3)
    缓冲数据,请参见下面的原因)
  • d
    的第一个fork生成进程
    b
    ,在执行第二个
    fork(2)
    (获取进程
    a
    )后,等待它完成,然后打印
    B0
  • b
    的第二个
    fork()
    (好吧,
    b
    是在列表的第一个fork之后创建的,并且只执行一个fork,但它是列表中的第二个fork),生成进程
    a
    ,打印
    A0
    ,然后退出,使进程
    b
    能够在
    等待(2)之后继续
    调用并打印
    B0
    ,这将强制顺序始终为
    A0
    B0
    之前
  • 第三个
    fork()
    生成进程
    c
    ,其任务是打印
    c
    退出(3)
    。(这样就不会输出
    C0
    ,而只输出
    C
  • 由于
    d
    不等待它的两个子项中的任何一个,一旦打印了
    D0
    ,它
    退出(3)
    s,使shell输出提示
    ~$
    ,并等待新命令。这将强制在shell提示之前执行命令
    D0
  • ^C
    是您按下的控件-C,认为程序仍在运行,它使shell在新行中发出第二个提示
就等待其子进程的唯一进程而言,只有shell(强制在
D0
之后打印提示)和进程
b
等待进程
a
(强制总是在
B0
之前打印
A0
)允许任何其他顺序,取决于系统如何安排进程。这包括提示。认为消息总是在所有任务执行结束时打印
shell
    `-d
      +-b
      | `-a
      `-c
printf("D");
...
printf("0");