0

Consider the following code running under Solaris 11.3:

int main(void) {
    pid_t pid = fork();
    if (pid > 0) {
        printf("[%ld]: Writing from parent process\n", getpid());
    }
    if (pid == 0) {
        execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
        perror("exec failed");
        exit(1);
    }
 }

Whenever I run it, the "Writing from parent" line is always output last. I would not be surprised with that result if my school task wasn't to use wait(2) in order to print that line only after the child process has finished. Why does this happen and how to ensure that this line is printed before the child process executes cat (or the order is at least undefined), so I can safely use wait(2) or waitpid(2) to tackle that?

  • It might be printf buffering. Add a fflush(stdout); after the printf – Rui F Ribeiro Mar 9 '16 at 17:26
  • @RuiFRibeiro it's still the same – Dmitry Serov Mar 9 '16 at 17:29
  • strange. In theory they should execute apparently at the same time....should be more or less random where one or another comes first, I think. – Rui F Ribeiro Mar 9 '16 at 17:33
  • and if you replace printf for putchar('c'); ? – Rui F Ribeiro Mar 9 '16 at 17:34
  • You can't assume any order between different threads (and a process is just one or more threads running in the same address space). If you want things to happen in a particular order you have to write code to ensure that's the order things happen in. Why are you seeing the child run first? Because that's what the OS happened to do on your hardware under your environment when you observed it. So far. If you really want to know what happened, you can use dtrace and/or dig into probably-pretty-close-to-Solaris 11.3 source code at src.illumos.org/source – Andrew Henle Mar 9 '16 at 18:54
2

As @AndrewHenle commented, depending on the system to schedule your processes in a specific sequence is unsafe and unjustified. Even when the scheduling appears to be consistent (as in your case), there is nothing preventing the operating system's implementers from altering the scheduler's behavior.

If order of operations between processes/threads is relevant, some form of communication is necessary.

For your scenario, a simple blocking read can do the job. Create a pipe before the fork. Then write to the pipe from the parent only after the parent has printed its message. Meanwhile, the child's attempt to read from the pipe will block its execution until the parent writes.

Neglecting error handling and unused pipe file descriptors in each process (which are usually explicitly closed after forking):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

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

int main(void) {

    char buf[1];
    int pipe_fds[2];
    pipe(pipe_fds);

    pid_t pid = fork();
    if (pid > 0) {
        printf("[%ld]: Writing from parent process\n", getpid());
        write(pipe_fds[1], "_", 1);
        wait(NULL);
    }
    if (pid == 0) {
        read (pipe_fds[0], buf, 1);
        execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
        perror("exec failed");
        exit(1);
    }

You should probably use wait in the parent, so that if it is run from a terminal, the child's output and shell prompt are not interleaved.

0

Consider this from the view of the kernel: it just thrashed all sorts of caches by setting up the child process, running that next probably reuses some of the new cache contents. Meanwhile, the parent might get scheduled on another CPU.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.