The fork() and vfork() syscalls are different.
The fork() syscall generates two identical processes with separate memory.
The vfork() syscall generates two processes that share the same memory.
With vfork() the parent will wait for the child terminates.
The parent inherites from the variables that the program is sharing.
So after the child was called, all variables modified inside the child will still be modified inside the parent.
Let’s see an example with this tutorial of both fork() and vfork() syscalls.
The Makefile and the header are the same for both examples.
So I give them first.
Same files for the project
Makefile
## BadproG.com
## Makefile
## Variables
NAME = forkIt
SRC = main.c
OBJ = $(SRC:.c=.o)
CFLAGS = -Wall -Werror -Wextra -pedantic -ansi -D_BSD_SOURCE
CC = gcc
## Rules
$(NAME) : $(OBJ)
$(CC) $(OBJ) -o $(NAME)
all : $(NAME)
clean :
rm -f $(OBJ)
fclean : clean
rm -f $(NAME)
re : fclean all
r : re
rm -f *~
rm -f *.o
h.h
/**
* Badprog.com
* h.h
*/
#ifndef H_H_
#define H_H_
typedef struct s_forky
{
int value;
} t_forky;
#endif /* H_H_ */
Using the fork() syscall
Details
If we want to be sure that the child will be executed before the parent process, we can add the wait() syscall inside the parent process:
...
else if (f > 0)
{
wait(&status);
printf("\n===== Begin Parent =====\n\n");
...
Otherwise the parent and the child will be executed at the same time!
For this example we cannot see the difference because the loop is too short.
But try to increment the i variable up to 100000 instead of 10, and you will see the difference.
main.c
/**
* Badprog.com
* main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "h.h"
int main()
{
int i;
int status;
pid_t f;
t_forky forky;
forky.value = 0;
i = 0;
status = 1;
f = fork();
if (f < 0)
{
fprintf(stderr, "Error: %s - fork() < 0 (%d)\n", strerror(errno), f);
}
else if (f > 0)
{
printf("\n===== Begin Parent =====\n\n");
printf("fork() = %d\n", f);
printf("getpid() = %d\n", getpid());
while (i < 10)
{
printf(" Parent - forky.value = %d\n", forky.value);
++forky.value;
++i;
}
}
else
{
printf("\n===== Begin Child =====\n\n");
printf("fork() = %d\n", f);
printf("getpid() = %d\n", getpid());
while (i < 10)
{
printf(" Child - forky.value = %d\n", forky.value);
++forky.value;
++i;
}
}
printf("status = %d\n", status);
printf("forky.value = %d\n\n", forky.value);
printf("===== End =====\n\n");
return 0;
}
Compiling
$ make r ; ./forkIt
Output
In this example, as the two processes are different, they use the loop to increment the forky.value up to 10.
===== Begin Parent =====
fork() = 18938
getpid() = 18937
Parent - forky.value = 0
Parent - forky.value = 1
Parent - forky.value = 2
Parent - forky.value = 3
Parent - forky.value = 4
Parent - forky.value = 5
Parent - forky.value = 6
Parent - forky.value = 7
Parent - forky.value = 8
Parent - forky.value = 9
status = 1
forky.value = 10
===== End =====
===== Begin Child =====
fork() = 0
getpid() = 18938
Child - forky.value = 0
Child - forky.value = 1
Child - forky.value = 2
Child - forky.value = 3
Child - forky.value = 4
Child - forky.value = 5
Child - forky.value = 6
Child - forky.value = 7
Child - forky.value = 8
Child - forky.value = 9
status = 1
forky.value = 10
===== End =====
Using the vfork() syscall
main.c
/**
* Badprog.com
* main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "h.h"
int main()
{
int i;
int status;
pid_t f;
t_forky forky;
forky.value = 0;
i = 0;
status = 1;
f = vfork();
if (f < 0)
{
fprintf(stderr, "Error: %s - fork() < 0 (%d)\n", strerror(errno), f);
}
else if (f > 0)
{
printf("\n===== Begin Parent =====\n\n");
printf("fork() = %d\n", f);
printf("getpid() = %d\n", getpid());
while (i < 10)
{
printf(" Parent - forky.value = %d\n", forky.value);
++forky.value;
++i;
}
}
else
{
printf("\n===== Begin Child =====\n\n");
printf("fork() = %d\n", f);
printf("getpid() = %d\n", getpid());
while (i < 10)
{
printf(" Child - forky.value = %d\n", forky.value);
++forky.value;
++i;
}
_exit(status);
}
printf("status = %d\n", status);
printf("forky.value = %d\n\n", forky.value);
printf("===== End =====\n\n");
return 0;
}
Compiling
$ make r ; ./forkIt
Output
In this example, as the two processes are sharing the same variables, the loop of the parent will never be executed because the i variable has already reach 10.
We can also see that I use the _exit(status) syscall at the end of the child.
===== Begin Child =====
fork() = 0
getpid() = 19013
Child - forky.value = 0
Child - forky.value = 1
Child - forky.value = 2
Child - forky.value = 3
Child - forky.value = 4
Child - forky.value = 5
Child - forky.value = 6
Child - forky.value = 7
Child - forky.value = 8
Child - forky.value = 9
===== Begin Parent =====
fork() = 19013
getpid() = 19012
status = 1
forky.value = 10
===== End =====
Well done, you made it.