fork() 开始执行

fork() start of execution

我是 unix 编程的新手,遇到了一些我不明白的事情。 这是以下代码片段:

#include <stdio.h>
#include <sys/types.h>

int main()
{
     printf("%d ", fork());
     return 0;
}

输出为:9298 0。 为什么子进程调用这个 printf ?在我的课程中,我被告知它在 fork() 调用之后执行所有操作。我哪里错了?

fork的结果传递给printf所以它在printf之前执行。您的代码相当于:

#include <stdio.h>
#include <sys/types.h>

int main()
{
     pid_t pid = fork();
     printf("%d ", pid);
     return 0;
}

当子进程启动时,它会在调用 fork 的地方启动,也就是 printf 调用的中间位置。

所以现在父进程 和子进程 都将完成自己单独的 printf 调用,每个都输出自己的 return 值。

你被告知的是不准确的。发生的情况是 fork 是该过程的(几乎相同的)副本。

因此它继续使用 fork() returning 父项和子项中的值。并且 printf 在这两个过程中继续。

想想 运行 程序创建一个 clone(这个解释有点讽刺,我稍后会谈到;))它自己和两个从病房的那个点开始做同样的事情。 从程序的内部角度来看的区别是 OS 赋予每个副本的 return 值。父程序接收子程序的进程 ID (pid),而子程序接收 0。这就是他们如何轻松区分彼此的方式。

fork 手册页中的片段:

下面的代码片段显示了有关“父”和“子”进程之间区别的更多详细信息:

   fork() creates a new process by duplicating the calling process.
   The new process is referred to as the child process.  The calling
   process is referred to as the parent process.

   The child process and the parent process run in separate memory
   spaces.  At the time of fork() both memory spaces have the same
   content.  Memory writes, file mappings (mmap(2)), and unmappings
   (munmap(2)) performed by one of the processes do not affect the
   other.

   The child process is an exact duplicate of the parent process
   except for the following points:

   *  The child has its own unique process ID, and this PID does not
      match the ID of any existing process group (setpgid(2)) or
      session.

   *  The child's parent process ID is the same as the parent's
      process ID.

   *  The child does not inherit its parent's memory locks
      (mlock(2), mlockall(2)).

   *  Process resource utilizations (getrusage(2)) and CPU time
      counters (times(2)) are reset to zero in the child.

   *  The child's set of pending signals is initially empty
      (sigpending(2)).

   *  The child does not inherit semaphore adjustments from its
      parent (semop(2)).

   *  The child does not inherit process-associated record locks
      from its parent (fcntl(2)).  (On the other hand, it does
      inherit fcntl(2) open file description locks and flock(2)
      locks from its parent.)

   *  The child does not inherit timers from its parent
      (setitimer(2), alarm(2), timer_create(2)).

   *  The child does not inherit outstanding asynchronous I/O
      operations from its parent (aio_read(3), aio_write(3)), nor
      does it inherit any asynchronous I/O contexts from its parent
      (see io_setup(2)).

克隆到 Linux

如果您使用 Linux,fork() 调用是 clone() 系统调用的包装器(实际上是一个子集)。有关这方面的更多信息,请参阅:

https://man7.org/linux/man-pages/man2/clone.2.html

嗯,函数的参数必须在调用函数之前计算...因此函数 printf() 必须在 fork() 调用 returns 之后调用,这是必然的。这对父进程和子进程以相同的方式发生。

由于前一个进程(父进程)在 fork() 调用中完全重复,它 returns 两次(一次在父进程中,一次在子进程中)都执行 printf() 但使用不同的第二个参数,父进程获得子进程的进程 ID,而子进程获得零。

如果 fork() 失败,情况会有所不同,只有一个进程(称为父进程的坏进程,因为没有子进程)会执行 printf() 调用,值为 -1 所以你应该得到

-1

在那种情况下。

最后,请注意:两个值的顺序可能不同,实际上第一个出现的数字是由第一个到达第一个 write() 系统调用的进程打印的数字(这是在终止之前调用 atexit() 处理程序,因为您在 printf() 调用中没有换行,因此,父子进程的输出得到缓冲,直到进程执行 exit() 函数和exit handlers were called) 你可以通过多次执行程序来检查这一点,你会看到第一个或第二个零,这取决于 cpu 的调度。但是这两个数字会一个接一个地出现(不可能两者都出现在输出中)这是因为两者都输出到同一个文件描述符并且内核阻止两个write()同时执行时间(文件的索引节点在系统调用期间被锁定,不允许其他进程输出其数据)