1

I have an assignment which gives me this code to transform into a code that makes the parent process wait for all children processes to finish. PS: the first code has 4 processes and needs to use waitpid to solve this.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
  pid_t p = fork();
  pid_t k = fork();

  if(p>0){
     printf("p=%d: PID = %d\n", p, getpid());
     sleep(45);
     exit(0);
  }
  else if(p==0){
     printf("p=%d: PID = %d\n", p, getpid());
     exit(0);
  }
  else if(p<0){
     printf("ERRO! p=%d\n", p);
     exit(p);
  }
}

I've tried this, but I think that this only works for only 1 child process and not for a lot of them.

int main(){

    pid_t p = fork(); 
    pid_t k = fork(); 

    if(p<0){
        printf("fodeu");
        exit(p);
    }
    else if(p==0){
        printf("");
        exit(0);
    }
    else{
        for(i=0;i<4;i++){
            int returnstatus; 
            waitpid(p,&returnstatus,0);

            if(returnstatus == 0){
                printf("o processo filho correu normalmente");
            }
            else if(returnstatus == 1){
                printf("o processo filho ardeu");
            }
        }
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
JackRS
  • 11
  • 1
  • 2
  • Does this answer your question? [Return from exit() with fork() is weirdly bitshifted](https://stackoverflow.com/questions/53035623/return-from-exit-with-fork-is-weirdly-bitshifted) – Joseph Sible-Reinstate Monica Apr 27 '20 at 19:16
  • Actually that's only one of your problems. The other is that you're ignoring `k`. – Joseph Sible-Reinstate Monica Apr 27 '20 at 19:18
  • 1
    You never use `k`, the return value from the second `fork()`. You need both `p > 0` and `k > 0` to identify the original process, which must do most of the waiting (it has two children). Your original child process must also wait. It is simplest to have each process wait until it has no children left — a while loop that invokes `wait()` or `waitpid()` and reports on the exit statuses. The processes without children will exit the loop immediately and terminate, allowing their parent process to continue. Note that your original process does not have 4 children; the for loop is inappropriate. – Jonathan Leffler Apr 27 '20 at 19:18
  • Don't forget to print a newline at the end of statements. If you're dealing with multiple processes, it's a good idea to include the PID of the process reporting in the output from `printf()`. – Jonathan Leffler Apr 27 '20 at 19:22

2 Answers2

1

This is one way to do it; there will be numerous others.

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

static void wait_for_kids(void);

int main(void)
{
    pid_t p = fork();
    pid_t k = fork();

    if (p > 0)
    {
        printf("p=%d: PID = %d\n", p, getpid());
        sleep(5);
        wait_for_kids();
        printf("%d: p = %5d, k = %5d - exiting\n", getpid(), p, k);
        exit(0);
    }
    else if (p == 0)
    {
        printf("p=%d: PID = %d\n", p, getpid());
        wait_for_kids();
        printf("%d: p = %5d, k = %5d - exiting\n", getpid(), p, k);
        exit(0);
    }
    else
    {
        printf("ERROR! p=%d\n", p);
        wait_for_kids();
        printf("%d: p = %5d, k = %5d - exiting\n", getpid(), p, k);
        exit(p);
    }
    /*NOTREACHED*/
}

static void wait_for_kids(void)
{
    int corpse;
    int status;
    int pid = getpid();

    while ((corpse = waitpid(0, &status, 0)) > 0)
        printf("%d: child %d exited with status 0x%.4X\n", pid, corpse, status);
}

Example output:

p=43445: PID = 43444
p=43445: PID = 43446
p=0: PID = 43445
p=0: PID = 43447
43447: p =     0, k =     0 - exiting
43445: child 43447 exited with status 0x0000
43445: p =     0, k = 43447 - exiting
43446: p = 43445, k =     0 - exiting
43444: child 43445 exited with status 0x0000
43444: child 43446 exited with status 0x0000
43444: p = 43445, k = 43446 - exiting
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

This won't do your assignment, but I hope it is advice enough to get you going. The assignment appear to be a riddle around fork(), your teacher has good taste :-)

fork() is different. It returns twice.

  • In the parent it returns the process ID of the created process.
  • In the child it returns 0; a process can always determine its PID using getpid()

Actually, the assignment is not good taste. Usually code using `fork() never lets any branch escape into enclosing code to avoid complete bullshit. Like so,

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t pid = fork();
    if (pid == 0 /*child*/) {
        printf("PID %d (child) doing work\n", pid);
        sleep(5);
        exit(0); // don't let it continue (leak) into parent code
    }
    else if (pid > 0 /*parent*/) {
        int status;
        pid_t terminated;

        printf("PID %d (parent) waiting for child PID %d\n", getpid(), pid);

        terminated = waitpid(pid, &status, 0);
        if (terminated == -1) {
            perror("waitpid");
            exit(1);
        }

        if (WIFEXITED(status))
            printf("child exited normally with status %d\n", WEXITSTATUS(status));
        else
            printf("hm. child died otherwise. see 'man waidpid' for more\n");
    }

    return 0;
}

With this in mind, look at these two innocent looking lines,

pid_t p = fork(); // two processes after this
pid_t k = fork(); // executed by **two** processes, again duplicating

So, after these two lines we have four processes executing the rest of the code in parallel. This is the point where brains explode. What does the leaked child of the k line do when it asks what p's value is?

Look at the output of this little program, to see what's the effect of leaking.

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

int main(){
  printf("MAIN PID %d\n", getpid());

  fork();
  fork();

  printf("PID %d, PPID %d\n", getpid(), getppid());
  return 0;
}