Edit: Well, my brain apparently autocompleted pid[1] to pid[0]. So the first question is answered by me being blind.
We were given following code example by university, I added a print call to better understand what is actually happening, with the REAL return values of everything.
I thought I understand how forking and assigning processIDs works. But I don't.
I don't understand two particular things:
I am new to Stackoverflow, thank you in advance for any help!
int v[3] = {0, 0, 0};
void handler(int sig) {
v[0]++;
}
int main() {
int pid[3];
signal(SIGUSR1, handler);
printf("Main Process ID: %d\n", getpid());
pid[0] = fork();
pid[1] = getpid();
pid[2] = fork();
if (pid[0] == pid[2]) {
v[1]++;
sleep(4);
} else if (pid[1] == getppid()) {
sleep(3);
v[2]++;
sleep(2);
} else if (pid[1] == getpid()) {
sleep(1);
v[2]++;
kill(pid[2], SIGUSR1);
wait(NULL);
if (pid[0] > 0) {
v[1]++;
wait(NULL);
}
}
printf("ppid %d, processID %d, pid0 %d, pid1 %d, pid2 %d\n", getppid(), getpid(), pid[0], pid[1], pid[2]);
printf("%d %d %d\n", v[0], v[1], v[2]);
}
Result:
Main Process ID: 286161
// 2. Fork (I assume)
ppid 286162, processID 286164, pid0 0, pid1 286162, pid2 0
1 1 0
// 2. Fork (I assume)
ppid 286161, processID 286162, pid0 0, pid1 286162, pid2 286164
0 0 1
// 1. Fork (I assume)
ppid 286161, processID 286163, pid0 286162, pid1 286161, pid2 0
1 0 1
// Main Process
ppid 154332, processID 286161, pid0 286162, pid1 286161, pid2 286163
0 1 1
Fork returns 0 to the child and the PID of the child to the parent.
First, let's look at this:
pid[0] = fork(); // <-- forks child_1. Returns PID(child_1) in parent, 0 in child_1
pid[1] = getpid(); // <-- Returns PID(parent) in parent, PID(child_1) in child_1
pid[2] = fork(); // <-- Forks child_2 from parent, forks child_3 from child_1. Returns PID(child_2) in parent, 0 in child_2, PID(child_3) in child_1, 0 in child_3
The first fork
spawns one child process, off of the parent. When fork is called the second time, there are two copies of the program running, so two processes are created: one from the original parent (ie. a sibling of child_1), and another from the first child (a grand-child of the original parent).
So for this:
1) ppid 286162, processID 286164, pid0 0, pid1 286162, pid2 0
2) ppid 286161, processID 286162, pid0 0, pid1 286162, pid2 286164
3) ppid 286161, processID 286163, pid0 286162, pid1 286161, pid2 0
4) ppid 154332, processID 286161, pid0 286162, pid1 286161, pid2 286163
I'll give each line a name: (1) is child_3, (2) is child_1, (3) is child_2, and (4) is the parent.
It's easier if you draw it out and step through it line-by-line.
Start with this:
SHELL
|
Parent
Then call fork
:
SHELL
|
Parent
/
child_1
In parent: PID[0] = pid_of(child_1)
In child_1: PID[0] = 0
Next, the call to getpid
.
In Parent: PID[1] = pid_of(parent)
In child_1: PID[1] = pid_of(child_1)
then the second fork
:
SHELL
|
Parent
/ \
child_1 child_2
|
child_3
In parent: PID[2] = pid_of(child_2)
In child_1: PID[2] = pid_of(child_3)
In child_2: PID[0]
and PID[1]
are inherited from parent, so PID[0]=pid_of(child_1)
, PID[1] = pid_of(parent)
, and PID[2] = 0
in child_3: PID[0]
and PID[1]
are inherited from child_1, so PID[0] = 0
, PID[1] = pid_of(child_1)
, and PID[2] = 0