【问题标题】:Sequence of print statement in fork() syatem callfork() 系统调用中的打印语句序列
【发布时间】:2017-07-25 09:21:35
【问题描述】:

为了更好地理解 fork() 系统调用,我在 fork() 和 print 语句之间随机播放,但卡在这样一个代码中,代码是

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
   printf("\n my process id %d \n",getpid());
   pid_t pid1=fork();
   printf("\nPID:=%d fork returned %d\n",getpid(),pid1);
   pid_t pid2=fork();
   printf("\nPID:=%d fork returned %d\n",getpid(),pid2);
   pid_t pid3=fork();
   printf("\nPID:=%d fork returned %d\n",getpid(),pid3);
   return 0;
}

这是获得的输出-:

我无法获得它所遵循的打印顺序。我唯一得到的是首先执行 PID 5079 的进程,并且对于所有 fork() 系统调用,它正在将子 PID 返回给父进程进程。我没有得到进一步的序列。

【问题讨论】:

  • 你知道fork是做什么的吗?这个怎么运作 ?它的返回值?看来您只是在没有真正考虑的情况下使用它。一旦产生了一个新进程,就无法保证谁先运行。所以你可以期待任何输出。接下来由你决定:看看 fork() 系统调用的返回值是什么。

标签: operating-system fork computer-science system-calls


【解决方案1】:

fork() 乍一看可能有点令人困惑,但实际上它非常简单。它所做的是将当前进程复制到另一个内存位置的新进程中(复制所有内容、其数据、代码、当前指令……)。

所以我们从一个 pid = 5079 的进程开始,当我们进行 fork 调用时,创建了一个 pid = 5080 的子进程,它的代码与父进程相同。

 // Parent Process //                    // Child Process //
 #include<stdio.h>                       #include<stdio.h> 
 #include<unistd.h>                      #include<unistd.h>
 #include<stdlib.h>                      #include<stdlib.h>
 int main()                              int main()
 {                                       {
    printf("\...                            printf("\...
    pid_t pid1=fork();                      pid_t pid1=fork(); 
    printf("\nPI...    //Next line//        printf("\nPI...    //Next line//
    pid_t pid2=fork();                      pid_t pid2=fork();
    printf("\nPID:=...                      printf("\nPID:=...
    pid_t pid3=fork();                      pid_t pid3=fork();
    printf("\nPID:=...                      printf("\nPID:=...
    return 0;                               return 0;
 }                                        }

在继续看代码之前,fork调用的返回值如下:在调用fork()的进程内部,返回值为子进程的pid(父进程中pid1变量=5080) ,而在子进程内部,输出为0(子进程中的pid1变量=0)。

所以fork之后的print语句会被父进程和子进程执行,getpid()值不同,pid1值不同,父进程getpid()=5079,pid1=子进程的pid=5080(你可以在输出的第三行看到这一点)。子进程会自己做打印语句,getpid() = 5080 and pid1 = 0,你可以在输出的第8行看到这个,但是为什么是第8行!!!

操作系统调度进程,也就是说,它决定 CPU 将在哪个进程上工作以及工作多长时间。所以看起来操作系统决定父进程(pid = 5079)应该运行一段时间,而让子进程(pid = 5080)等待CPU执行它的指令。

所以进程 5079 继续下一个分叉,创建一个 pid = 5081 的新子进程。然后它在第三行打印我们期望的内容,然后它继续到最后一个分叉创建进程 5082,打印我们想要的期望在第四行,然后终止(进程 5079 终止,留下 5080,5081,5082 等待,并且被操作系统采用,它们需要有父级,但这对输出并不重要)。

现在 5079 终止了,我们有 3 个进程在内存中等待 CPU 运行它们。操作系统必须决定运行哪个进程,而且它似乎已经选择了最接近终止的进程,也就是进程 5082,我们来看看每个进程的剩余指令:

  // process 5082 //      // process 5081 //     // process 5080 //
  printf("\nP...          printf("\nP...         printf("\nP...
  return 0;               pid_t pid3=fork();     pid_t pid2=fork();
                          printf("\nP...         printf("\nP...
                          return 0;              pid_t pid3=fork();
                                                 printf("\nP...
                                                 return 0;

为什么这是剩下的代码?像我们之前看到的那样,在其他进程中由 fork 创建的任何进程都将在该 fork 语句之后开始执行。所以进程 5082 打印了第 5 行然后终止(它的值 pid3 = 0 因为它是 5079 的孩子)。终止 5082 后,5081 占用 CPU,并打印第 6 行,然后创建进程 5085,正如我们在第 6 行中看到的那样(为什么不按顺序排列 5083?也许操作系统在执行代码期间创建了一些进程)。

在打印第 6 行后,进程 5081 已终止。现在我们在内存中有 5080 和 5085。您现在应该能够遵循该模式,选择运行 5080,创建 5086 和 5087 然后终止。然后 5085 运行,然后是 5087,它最后只有 print 语句,然后都终止了,我们只剩下 5086 打印了,最后一个 fork 创建了 5088,然后像 5088 打印后一样终止。

操作系统是一个令人着迷的领域,它的乐趣超越了系统调用,如果你对此感兴趣,我会推荐这本书,这是我大学时学习的: https://www.amazon.com/Operating-System-Concepts-Abraham-Silberschatz/dp/0470128720

【讨论】:

    猜你喜欢
    • 2012-02-02
    • 2015-12-22
    • 1970-01-01
    • 2012-05-28
    • 2013-10-19
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2016-12-14
    相关资源
    最近更新 更多