简体   繁体   中英

Understanding fork() order in C

So I have this program I'm trying to understand, its from an old exam but I just cant get a grip of it. How do I know the order of the forks and how the variables are changed?

static int g = -1;

int main(int argc, char *argv[])
{
    int v = 0;
    pid_t p;

    while (v++ < 6)
        if ((p = fork()) < 0) {
            perror("fork error");
            return 1;
        } else if (p == 0) {
            v++;
            g--;
        } else {
            g++;
            v+=3;
        if (waitpid(p, NULL, 0) != p) {
            perror("waitpid error");
            return 1;
        }
    }
    printf("mypid = %d parentpid = %d p = %d v = %d g = %d\n",
    getpid(), getppid(), p, v, g);
    return 0;
}

The call to fork() both starts a new process and continues the old one. If there is some kind of error, it returns an error value. All errors and only errors are negative numbers. This is what the first if block checks.

In the new process, fork() returns 0. The branch that increments v and decrements g is therefore called only in the child process, not the parent.

In the original process, the fork() function returns the process identifier (PID) of the daughter process, which is a positive integer. (This will later be passed to waitpid() . Therefore, the branch that decrements v and increments g is only called in the parent process, not the child.

Each process has its own copy of v and g . (That's the main difference between a process and a thread: threads share memory.) On a modern SMP operating system, what will happen is that the child process gets a copy of the parent's memory map. but these refer to the same pages of physical memory until one process or the other writes to them. When that happens, a copy is made of that page of memory and both processes now get their own, different copies.

The way modern Linux kernels implement fork() , the child process will continue before the parent does. This made a significant difference to performance. Most programs that call fork() immediately have the child process call exec() to start a new program. That means it isn't going to need its copy of the parent's memory at all. (There is a newer, simpler way to start a different program in a new process now, posix_spawn() .) The parent process, on the other hand, almost always keeps running and modifying its memory. Therefore, giving the child the chance to declare that it's going to discard the memory it inherited means that the parent doesn't need to worry about leaving an unmodified copy of any memory pages for its children, and the kernel does not have to go through the rigmarole of copy-on-write.

In practice, though, any decent compiler will keep both local variables in registers, so this issue will not arise.

On the next iteration of the loop, which only happens after the child process terminates, a new child process is spawned using the updated values of the parent's variables. Each child process also continues to run the loop with the same values of v and g that it inherited from its parent.

Each call to fork generates its own process with its own variables, which are copied at the time of the call (logically; optimization may change when the actual copy happens, but not in a way that'll change the outcome).

So when you enter the loop, v gets incremented to 1, then you fork. At this point the parent process has g=-1, v=1, p= and the new child has g=-1, v=1, p=0. The parent then drops into the else case, incrementing g to 0 and v to 4 and then waiting for the child to complete, whereas the child drops into the "else if (p == 0)", increments v to 2, decrements g to -2, and goes around the loop again.

From there, you've hopefully now got enough information to follow the logic as the next two child processes get forked off, finish off the loop, and print their respective results. When they do, the first child will also come to the end of its waitpid with v=6, drop out of the loop, and print its results.

At this point, the parent will unblock, go around the loop one more time (forking off one more child along the way), and (once that child has completed) drop out of the loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM