Mandatory task 1 ING2504 Fall 2025¶
You MUST watch this lecture BEFORE you start doing this task!
When you have completed all three parts of this mandatory task, show/demonstrate your solution to Erik
Part 1: Understanding fork()¶
Goal¶
Write a C program that creates exactly four processes in total using fork(). The original process (the root parent) should create a child; both the parent and that child should each create one additional child, resulting in this two-level tree:
Level 0: P0 (original parent)
├─ Level 1: C1 (child of P0)
│ └─ Level 2: C3 (child of C1)
└─ Level 1: C2 (child of P0)
Create a file four.c with the following starter code, and you only have
to add code where it says YOUR CODE HERE:
// four.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
pid_t pid1, pid2;
int depth = 0;
// this is a statement to make stdout unbuffered so each
// process prints its line immediately, just leave as is
setvbuf(stdout, NULL, _IONBF, 0);
// TODO 1: First fork. After this, you should have 2 processes:
// - The original parent (depth 0)
// - The first child (depth 1)
// YOUR CODE HERE (fork)
if (pid1 < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
// YOUR CODE HERE (if test)
// We are the child created by the first fork
depth = 1;
// TODO 2: Second fork. Both current processes should execute
// exactly one more fork, creating one new child each.
// YOUR CODE HERE (fork)
if (pid2 < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
// YOUR CODE HERE (if test)
// We are the child created by the second fork
depth++; // child is one level deeper than its parent
// TODO 3: Print exactly one line per process:
// Format: depth=<d> pid=<PID> ppid=<PPID>
// add zero, one or two tabs (\t) dependent on depth
if (depth == 0) {
// YOUR CODE HERE (printf)
} else if (depth == 1) {
// YOUR CODE HERE (SAME printf but with \t)
} else if (depth == 2) {
// YOUR CODE HERE (SAME printf but with \t\t)
}
// Reap any children (if we have any) to avoid zombies, leave as is
while (wait(NULL) > 0) {
// loop until no more children
}
return 0;
}
Running the program should output something like this:
$ ./four
depth=0 pid=3859940 ppid=2431311
depth=1 pid=3859942 ppid=3859940
depth=1 pid=3859941 ppid=3859940
depth=2 pid=3859943 ppid=3859941
Hints¶
fork()returns 0 in the child, and the child’s PID in the parent. Use this to decide paths.- Use
getpid()andgetppid()to print IDs.
Part 2: Understand fork()-exec() combination and simple synchronization¶
(a) Write a C-program mycow.c¶
- Start from p3.c
- Instead of executing the wordcount program, the child processes should
execute
cowsay(note: you might have to install the cowsay program) with arguments provided on the command line - The program should loop over the command line arguments and fork a child
process for each of them and execute cowsay using the system call
execvpin the same way as p3.c. - The program should output in the same order as the command line
arguments are provided, and only one cowsay should be executed at a time
(in other words: use
waitpidfor this simple synchronization).
Here as an example of how mycow should run:
$ ./mycow "Let's moo-ve!" "Holy cow!" "Deja-moo" "Bullshit"
_______________
< Let's moo-ve! >
---------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
___________
< Holy cow! >
-----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
__________
< Deja-moo >
----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
__________
< Bullshit >
----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$
If you don't synchronize correctly with waitpid, you might get something
like this:
$ ./mycow "Let's moo-ve!" "Holy cow!" "Deja-moo" "Bullshit"
_______________
__________
___________
< Let's moo-ve! >
< Deja-moo >
< Holy cow! >
---------------
----------
-----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
__________
< Bullshit >
----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$
(b) Understanding simple parallelization from the command line¶
Run your cowsay program ten times in sequence:
Scroll up to see that the output is correct (no lines are mixed/interleaved) all the time.
Replace the last ;with &. Run it again.
- Is the output still correct?
- What is different in the way the program is run now?
- (Optional difficult task) How can you fix this?