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.
## 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
/** * Badprog.com * h.h */ #ifndef H_H_ #define H_H_ typedef struct s_forky { int value; } t_forky; #endif /* H_H_ */
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.
/** * 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; }
make r ; ./forkIt
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 =====
/** * 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; }
make r ; ./forkIt
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!
Comments
Mayank (not verified)
Friday, September 30, 2016 - 2:19pm
Permalink
Good information, but this is
Good information, but this is not true in case of AIX.
Add new comment