fork() 如何知道何时返回 0? [英] How does fork() know when to return 0?

查看:23
本文介绍了fork() 如何知道何时返回 0?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下面的例子为例:

int main(void)
{
     pid_t  pid;

     pid = fork();
     if (pid == 0) 
          ChildProcess();
     else 
          ParentProcess();
}

如果我错了,请纠正我,一旦 fork() 执行,就会创建一个子进程.现在通过这个 answer fork() 返回两次.那是一次用于父进程,一次用于子进程.

So correct me if I am wrong, once fork() executes a child process is created. Now going by this answer fork() returns twice. That is once for the parent process and once for the child process.

这意味着两个独立的进程在 fork 调用期间而不是在它结束之后出现.

Which means that two separate processes come into existence DURING the fork call and not after it ending.

现在我不明白它如何理解如何为子进程返回 0,为父进程返回正确的 PID.

Now I don't get it how it understands how to return 0 for the child process and the correct PID for the parent process.

这真的很令人困惑.这个 answer 指出 fork() 通过复制进程的上下文信息并手动将返回值设置为 0 来工作.

This where it gets really confusing. This answer states that fork() works by copying the context information of the process and manually setting the return value to 0.

首先我说对任何函数的返回都放在一个寄存器中是对的吗?因为在单处理器环境中,一个进程只能调用一个只返回一个值的子程序(如果我错了,请纠正我).

First am I right in saying that the return to any function is placed in a single register? Since in a single processor environment a process can call only one subroutine that returns only one value (correct me if I am wrong here).

假设我在例程中调用函数 foo() 并且该函数返回一个值,该值将存储在一个寄存器中,比如 BAR.每次函数想要返回一个值时,它都会使用一个特定的处理器寄存器.所以如果我能够手动更改进程块中的返回值,我就能更改返回给函数的值,对吗?

Let's say I call a function foo() inside a routine and that function returns a value, that value will be stored in a register say BAR. Each time a function wants to return a value it will use a particular processor register. So if I am able to manually change the return value in the process block I am able to change the value returned to the function right?

那么我认为 fork() 的工作原理是否正确?

推荐答案

它的工作原理在很大程度上是无关紧要的 - 作为在某个级别工作(即编写 UNIX API 代码)的开发人员,您真的只需要知道它有效.

How it works is largely irrelevant - as a developer working at a certain level (ie, coding to the UNIX APIs), you really only need to know that it works.

话虽如此,但认识到好奇心或需要深入了解通常是一个很好的特征,有很多方法可以做到这一点.

Having said that however, and recognising that curiosity or a need to understand at some depth is generally a good trait to have, there are any number of ways that this could be done.

首先,您认为一个函数只能返回一个值的论点就目前而言是正确的,但您需要记住,在进程拆分后,实际上有两个函数实例运行,每个进程一个.它们大多相互独立,可以遵循不同的代码路径.下图可能有助于理解这一点:

First off, your contention that a function can only return one value is correct as far as it goes but you need to remember that, after the process split, there are actually two instances of the function running, one in each process. They're mostly independent of each other and can follow different code paths. The following diagram may help in understanding this:

Process 314159 | Process 271828
-------------- | --------------
runs for a bit |
calls fork     |
               | comes into existence
returns 271828 | returns 0

您希望在那里看到 fork单个实例只能返回一个值(与任何其他 C 函数一样)但实际上有多个实例在运行,这这就是为什么据说在文档中返回多个值.

You can hopefully see there that a single instance of fork can only return one value (as per any other C function) but there are actually multiple instances running, which is why it's said to return multiple values in the documentation.

这是关于它如何工作的一种可能性.

Here's one possibility on how it could work.

fork() 函数开始运行时,它会存储当前进程 ID (PID).

When the fork() function starts running, it stores the current process ID (PID).

然后,当需要返回时,如果PID与存储的相同,则它是父级.否则就是孩子.伪代码如下:

Then, when it comes time to return, if the PID is the same as that stored, it's the parent. Otherwise it's the child. Pseudo-code follows:

def fork():
    saved_pid = getpid()

    # Magic here, returns PID of other process or -1 on failure.

    other_pid = split_proc_into_two();

    if other_pid == -1:        # fork failed -> return -1
        return -1

    if saved_pid == getpid():  # pid same, parent -> return child PID
        return other_pid

    return 0                   # pid changed, child, return zero

请注意,split_proc_into_two() 调用中有很多神奇之处,而且几乎可以肯定它在幕后根本不会以这种方式工作(a).只是为了说明围绕它的概念,基本上是:

Note that there's a lot of magic in the split_proc_into_two() call and it almost certainly won't work that way at all under the covers(a). It's just to illustrate the concepts around it, which is basically:

  • 获取拆分前的原始 PID,两个进程拆分后的原始 PID 将保持相同.
  • 进行拆分.
  • 获取拆分后的当前PID,这在两个进程中会不同.

您可能还想看看这个答案,它解释了 fork/exec 哲学.

You may also want to take a look at this answer, it explains the fork/exec philosophy.

(a) 这几乎肯定比我解释的要复杂.例如,在 MINIX 中,对 fork 的调用最终在内核中运行,内核可以访问整个进程树.

(a) It's almost certainly more complex than I've explained. For example, in MINIX, the call to fork ends up running in the kernel, which has access to the entire process tree.

它只是将父进程结构复制到子进程的空闲槽中,如下所示:

It simply copies the parent process structure into a free slot for the child, along the lines of:

sptr = (char *) proc_addr (k1); // parent pointer
chld = (char *) proc_addr (k2); // child pointer
dptr = chld;
bytes = sizeof (struct proc);   // bytes to copy
while (bytes--)                 // copy the structure
    *dptr++ = *sptr++;

然后对子结构稍作修改以确保其适合,包括以下行:

Then it makes slight modifications to the child structure to ensure it will be suitable, including the line:

chld->p_reg[RET_REG] = 0;       // make sure child receives zero

所以,基本上与我提出的方案相同,但使用数据修改而不是代码路径选择来决定返回给调用者的内容 - 换句话说,您会看到如下内容:

So, basically identical to the scheme I posited, but using data modifications rather than code path selection to decide what to return to the caller - in other words, you'd see something like:

return rpc->p_reg[RET_REG];

fork() 的末尾,以便根据它是父进程还是子进程返回正确的值.

at the end of fork() so that the correct value gets returned depending on whether it's the parent or child process.

这篇关于fork() 如何知道何时返回 0?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆