fork返回什么?

31

如果成功,子进程的PID将在父线程中返回, 并且在子线程中返回0。

p = fork();

我对这个函数的手册页感到困惑,p 是等于 0 还是 PID


有人可以把 getpid() 包含进来吗? 子进程中的 getpid() 返回 0? - Shrinidhi
@Shrinidhi:fork()也是这样的。 - BoltClock
2
它既是pid也是0。当调用fork时,程序会“分裂”成两个——它本身和邪恶的副本。在原始程序中,它是0。在邪恶的副本程序中,它是pid。 - Stephen Chung
6
我认为fork是返回食物的一小部分,但我可能错了。;-) - Thomas Matthews
有什么需要困惑的呢?你引用的文档非常清晰明了。 - user207421
8个回答

71
我不确定手册怎么能更清晰!fork()会创建一个新的进程,所以您现在有两个相同的进程。为了区分它们,fork()的返回值不同。在原始进程中,您会得到子进程的PID。在子进程中,您会得到0。
因此,标准用法如下:
p = fork();
if (0 == p)
{
    // We're the child process
}
else if (p > 0)
{
    // We're the parent process
}
else
{
    // We're the parent process, but child couldn't be created
}

2
@编译器:不,调用fork后,旧进程和新创建的进程都会继续执行 - Joachim Sauer
1
@编译器:没有递归。正如@Joachim所说,新进程不会从main的开头开始,它会直接在fork()调用之后继续执行。 - Oliver Charlesworth
4
如果没有创建新的进程,那么这意味着fork 失败了,它会返回-1而不是0,并适当地设置errno。这个操作是在原始进程中执行的(由于没有创建任何进程,因此其不是父进程)。 - zwol
新进程是否从脚本的新运行副本的顶部开始?还是立即在fork语句下面开始?如何将值传递给分叉的进程? - Dennis
@OliCharlesworth 当我们进行fork操作时,程序计数器会发生什么变化?在创建一个新的子进程时,子进程中的程序计数器指向哪里? - codey modey
显示剩余7条评论

35
p = fork();
/* 假设没有错误 */
/* 你现在有两个程序运行 */
--------------------
if (p > 0) {                 |           if (p == 0) {
  printf("parent\n");         |             printf("child\n");
  ...                         |             ...

9
进程被组织成一个有向树,你只知道你的单亲(getppid())。简而言之,fork()会像其他许多系统函数一样在出错时返回-1,非零值对于fork调用的发起者(父进程)来说是有用的,以便知道它的新子进程pid。
没有什么比例子更好的了。
/* fork/getpid test */
#include <sys/types.h>
#include <unistd.h>     /* fork(), getpid() */
#include <stdio.h>

int main(int argc, char* argv[])
{
    int pid;

    printf("Entry point: my pid is %d, parent pid is %d\n",
           getpid(), getppid());

    pid = fork();
    if (pid == 0) {
        printf("Child: my pid is %d, parent pid is %d\n",
               getpid(), getppid());
    }
    else if (pid > 0) {
        printf("Parent: my pid is %d, parent pid is %d, my child pid is %d\n",
               getpid(), getppid(), pid);
    }
    else {
        printf("Parent: oops! can not create a child (my pid is %d)\n",
               getpid());
    }

    return 0;
}

结果如下(在本例中,bash 的进程 ID 为 2249):

Entry point: my pid is 16051, parent pid is 2249
Parent: my pid is 16051, parent pid is 2249, my child pid is 16052
Child: my pid is 16052, parent pid is 16051

如果您需要在父进程和子进程之间共享一些资源(如文件、父进程ID等),请查看clone()函数(适用于GNU C库,以及可能适用于其他一些库)。


8

这是很酷的部分。 它等同于双方。

嗯,并不完全是这样。但是一旦fork返回,你现在有两份正在运行的程序副本! 两个进程。你可以将它们想象成交替的宇宙。在一个宇宙中,返回值是0。在另一个宇宙中,它是新进程的ID

通常你会像这样拥有:

p = fork();
if (p == 0){
    printf("I am a child process!\n");
    //Do child things
}
else {
    printf("I am the parent process! Child is number %d\n", p);
    //Do parenty things
}

在这种情况下,两个字符串都会被打印出来,但是由不同的进程完成!

1
你把父子关系搞反了。 - interjay

8
一旦执行fork,您就会拥有两个进程。该调用会向每个进程返回不同的值。
如果您执行以下操作:
int f;
f = fork();
if (f == 0) {
  printf("I am the child\n");
} else {
  printf("I am the parent and the childs pid is %d\n",f);

}

你会看到两条信息被打印出来。它们是由两个独立的进程打印的。这是你可以区分所创建的两个进程的方法。

当返回0时,这意味着fork没有创建进程,对吗? - compiler
5
不。这意味着您正在子进程中。"不创建进程"表示只会有一个进程。如果返回-1,则表示未创建任何子进程。手册指出了这一点。 - Noufal Ibrahim
什么情况下不会创建子进程?如果我在 while 循环中使用 fork(),是否会得到 -1 的返回值? - Heisenberg
1
可能由于任何原因。如果返回值为-1,则设置了errno,因此您将知道它失败的原因。 - Noufal Ibrahim

2
在父进程中调用fork()函数,然后生成一个子进程。在子进程生成时,fork()已经执行完毕。
此时,fork()准备返回,但是根据它是在父进程还是子进程中,它返回不同的值。在子进程中,它返回0,在父进程/线程中,它返回子进程的进程ID。

你的意思是在子进程中 fork 会被评估为 无操作 吗? - compiler
@编译器:在这种情况下,它没有副作用。但是根据调用它的位置,它的返回值会有所不同。 - BoltClock
@Noufal Ibrahim,我知道在子进程中0表示什么,但它是否也表示没有额外的进程被创建? - compiler
如果您调用fork一次,将会创建一个进程。我不明白您的问题。 - Noufal Ibrahim
@Noufal Ibrahim:我觉得我的回答表达不清楚。我已经编辑过了,也许现在更有意义了。 - BoltClock
显示剩余2条评论

1

Fork会创建一个重复的进程和一个新的进程上下文。当它返回0值时,表示子进程正在运行,但当它返回其他值时,表示父进程正在运行。通常我们使用wait语句,以便子进程完成并且父进程开始执行。


-1
我认为它的工作原理是这样的: 当pid = fork()时,代码应该在当前进程和子进程中执行两次。 所以这就解释了为什么if/else都会执行。 而且顺序是先执行当前进程,然后再执行子进程。

1
顺序不能保证(据我所知)。 - ctrl-alt-delor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接