UNIX & GNU/Linux - System calls - Difference between fork() and vfork()

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! laugh

Comments

Comment: 

Good information, but this is not true in case of AIX.

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.