fork, wait and exec calls
fork()
The fork() system call is used to create a new process.
Here're the sample codes.
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("This codes runs before fork() method is called\n");
int rc = fork();
if (rc < 0) printf("Error occurred when calling fork()\n");
else if (rc == 0) printf("This is the child process (pid : %d)\n", (int) getpid());
else printf("This is the parent process of %d (pid : %d)\n", rc, (int) getpid());
return 0;
}
If we run the codes in bash
ATWs-MacBook-Pro:os ATW$ ./a.out
This codes runs before fork() method is called
This is the parent process of 18153 (pid : 18152)
This is the child process (pid : 18153)
Firstly, we need to know what does fork() returns. It returns
- the PID of the child when it's a parent process
- 0 when it's a created child process
- a negative number when errors occurred running fork()
Intuitively, we can notice that fork() will run a copy of parent process. But why codes before fork() was not executed? This is because fork copies the current status of the parent process.
Note the output is not deterministic, i.e. the order is not certain. The CPU scheduler will determin which process runs at a given moment in time.
wait()
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(){
printf("This codes runs before fork() method is called\n");
int rc = fork();
if (rc < 0) printf("Error occurred when calling fork()\n");
else if (rc == 0) printf("This is the child process (pid : %d)\n", (int) getpid());
else {
int wc = wait(NULL);
printf("This is the parent process of %d (wc : %d) (pid : %d)\n", rc, wc, (int) getpid());
}
return 0;
}
Run it in bash
ATWs-MacBook-Pro:os ATW$ ./a.out
This codes runs before fork() method is called
This is the child process (pid : 19926)
This is the parent process of 19926 (wc : 19926) (pid : 19925)
In this example, wait() delays the parent execution so child process would run first. This output is deterministic.
exec()
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(){
printf("This codes runs before fork() method is called\n");
int rc = fork();
if (rc < 0) printf("Error occurred when calling fork()\n");
else if (rc == 0){
printf("This is the child process (pid : %d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); //strdup() simply copies string, wc means wordcounter
myargs[1] = strdup("p1.c"); // argument : file to count
myargs[2] = NULL; // end of array
execvp(myargs[0], myargs);
printf("This should NOT be printed.\n");
}
else {
int wc = wait(NULL);
printf("This is the parent process of %d (wc : %d) (pid : %d)\n", rc, wc, (int) getpid());
}
return 0;
}
Run it in bash
ATWs-MacBook-Pro:os ATW$ ./a.out
This codes runs before fork() method is called
This is the child process (pid : 21341)
23 92 685 p1.c
This is the parent process of 21341 (wc : 21341) (pid : 21340)
The execvp() is a counting program that tells us how many lines, words and bytes are found in the file.
Why it's cool?
Consider a shell, it's a running process. It shows you a prompt and wait for your input. It fork() a program when you type something. Using exec() to run the program and wait() for the end of execution.