1 /*------------------------------------------------------------------------
2 |
3 | File: fork01.c
4 |
5 | Description: Simple program creating a child process with fork()
6 | and printing the return value from fork()
7 |
8 | Usage: fork01
9 |
10 | Created: 5 Jan 15
11 | Author: glancast
12 | Modifications:
13 |
14 +-----------------------------------------------------------------------*/
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h> // for fork
18
19 int main(int argc, char* argv[])
20 {
21 int pid;
22
23 pid = fork();
24 printf("pid = %d\n", pid);
25
26 return 0;
27 }
1 /*------------------------------------------------------------------------
2 |
3 | File: fork02a.c
4 |
5 | Description: Another simple program creating a child process with fork()
6 | and printing the return value from fork(). But if the return is
7 | not 0 the process 'sleeps' for 1 second before printing.
8 |
9 |
10 | Usage: fork02a
11 |
12 | Created: 5 Jan 15
13 | Author: glancast
14 | Modifications:
15 |
16 +-----------------------------------------------------------------------*/
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h> // for fork
20
21 int main(int argc, char* argv[])
22 {
23 int pid1;
24 int pid2;
25
26 pid1 = fork();
27 pid2 = fork();
28 printf("pid = %d\n", pid);
29
30 return 0;
31 }
Horizontal lines represent the execution of one process.
Vertical inserted to indicate 'forking' a new process.
Example:
(In this example P represents the printf statement.)
19 int main(int argc, char* argv[])
20 {
21 int pid;
22
23 pid = fork();
24 printf("pid = %d\n", pid);
25
26 return 0;
27 }
Trace Graph:
-23---+--24--P---
|
+--24--P---
Output:
pid = 0
pid = ... (a value > 0)
OR
pid = ... (a value > 0)
pid = 0
Same graph, but abreviated to omit the line numbers:
---+--P---
|
+--P---
/** world.c */
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc, char *argv[])
5 {
6 printf("world begins\n");
7 printf("Hello, World!\n");
8 printf("world ends\n");
9 return 0;
10 }
Output:
world begins
Hello, World!
world ends
(source)
/** exec01.c */
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main(int argc, char *argv[])
6 {
7 printf("exec01 begins!\n");
8 execlp("world", "world", (char *) 0);
9 printf("exec01 ends!\n");
10 return 0;
11 }
Output:
exec01 begins
world begins
Hello, World!
world ends
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc, char *argv[])
5 {
6 for(int i = 0; argv[i] != 0; i++) {
7 printf("argv[%d] = '%s'\n", i, argv[i]);
8 }
9
10 return 0;
11 }
printArgs A B C
Output:
argv[0] = 'printArgs'
argv[1] = 'A'
argv[2] = 'B'
argv[3] = 'C'
1 /*------------------------------------------------------------------------
2 |
3 | File: exec02.c
4 |
5 | Description: Calls execlp to execute printArgs
6 | with "command line arguments".
7 |
8 | Created: 8 Jan 15
9 | Author: glancast
10 |
11 +-----------------------------------------------------------------------*/
12
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17
18 int main(int argc, char *argv[])
19 {
20 execlp("printArgs", "A", "B", "C", (char *) 0);
21 printf("execlp failed!\n");
22 return 0;
23 }
Output:
argv[0] = 'A'
argv[1] = 'B'
argv[2] = 'C'
1 /*------------------------------------------------------------------------
2 |
3 | File: exec03.c
4 |
5 | Description: Calls execlp to execute printArgs
6 | with "command line arguments", but so that
7 | printArgs gets the same arguments that it would
8 | if run by a shell.
9 |
10 | Created: 8 Jan 15
11 | Author: glancast
12 |
13 +-----------------------------------------------------------------------*/
14
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19
20 int main(int argc, char *argv[])
21 {
22 execlp("printArgs", "A", "B", "C", (char *) 0);
23 printf("execlp failed!\n");
24 return 0;
25 }
Output: (Same as runing printArgs from the command prompt.)
argv[0] = 'printArgs'
argv[1] = 'A'
argv[2] = 'B'
argv[3] = 'C'
The waitpid has several options, the simplest is to wait for any child it has created to terminate (either normally or abnormally)
int pid;
int status;
pid = waitpid(-1, &status, 0);
The -1 means wait for any child process to terminate.
The second parameter can be 0. In that case it is ignored. If not zero the integer 'status' contains information about how the child terminated and its exit or return value if it terminated normally.
If a process (the parent) calls fork() to create a process (the child), the parent doesn't automatically wait for the child to finish. The parent must call waitpid to do wait.
So if waitpid is not called, which process finishes first?
Either one could finish first.
If the parent finishes first, the child becomes an orphan and is adopted by a system process called init whose pid is 1.
If the child finishes first, it becomes a zombie.
The child is mostly dead, but the parent might call waitpid. So it's termination information must be retained until the parent either terminates or calls waitpid.
A server process typically creates a child process, but doesn't wait for it to terminate. Instead it tries to create more children.
Problem: This can lead to a lot of zombies. Solution should involve only calling waitpid (to finally get rid of child process when the child terminates.
How does the parent know when the child terminates?