Création et fin de processus

Jusqu'à présent, nous savons que chaque fois que nous exécutons un programme, un processus est créé et se terminerait après la fin de l'exécution. Que faire si nous devons créer un processus dans le programme et que nous souhaitons planifier une tâche différente pour celui-ci. Cela peut-il être réalisé? Oui, évidemment grâce à la création de processus. Bien sûr, une fois le travail terminé, il se terminera automatiquement ou vous pouvez le terminer si nécessaire.

La création de processus est réalisée grâce au fork() system call. Le processus nouvellement créé est appelé le processus enfant et le processus qui l'a lancé (ou le processus lorsque l'exécution est lancée) est appelé processus parent. Après l'appel système fork (), nous avons maintenant deux processus - les processus parents et enfants. Comment les différencier? Très simple, c'est grâce à leurs valeurs de retour.

Après la création du processus fils, voyons les détails de l'appel système fork ().

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

Crée le processus enfant. Après cet appel, il y a deux processus, le processus existant est appelé processus parent et le processus nouvellement créé est appelé processus enfant.

L'appel système fork () renvoie l'une des trois valeurs -

  • Valeur négative pour indiquer une erreur, c'est-à-dire l'échec de la création du processus enfant.

  • Renvoie un zéro pour le processus enfant.

  • Renvoie une valeur positive pour le processus parent. Cette valeur est l'ID de processus du processus enfant nouvellement créé.

Considérons un programme simple.

File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
   fork();
   printf("Called fork() system call\n");
   return 0;
}

Étapes d'exécution

Compilation

gcc basicfork.c -o basicfork

Exécution / Sortie

Called fork() system call
Called fork() system call

Note- Habituellement, après l'appel de fork (), le processus enfant et le processus parent effectuent des tâches différentes. Si la même tâche doit être exécutée, alors pour chaque appel à fork (), elle s'exécuterait 2 fois n fois, oùn est le nombre de fois que fork () est invoqué.

Dans le cas ci-dessus, fork () est appelé une fois, donc la sortie est imprimée deux fois (2 puissance 1). Si fork () est appelé, disons 3 fois, alors la sortie sera imprimée 8 fois (2 puissance 3). S'il est appelé 5 fois, il imprime 32 fois et ainsi de suite.

Après avoir vu fork () créer le processus enfant, il est temps de voir les détails du processus parent et des processus enfants.

Nom de fichier: pids_after_fork.c

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
   pid_t pid, mypid, myppid;
   pid = getpid();
   printf("Before fork: Process id is %d\n", pid);
   pid = fork();

   if (pid < 0) {
      perror("fork() failure\n");
      return 1;
   }

   // Child process
   if (pid == 0) {
      printf("This is child process\n");
      mypid = getpid();
      myppid = getppid();
      printf("Process id is %d and PPID is %d\n", mypid, myppid);
   } else { // Parent process 
      sleep(2);
      printf("This is parent process\n");
      mypid = getpid();
      myppid = getppid();
      printf("Process id is %d and PPID is %d\n", mypid, myppid);
      printf("Newly created process id or child pid is %d\n", pid);
   }
   return 0;
}

Étapes de compilation et d'exécution

Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628
Newly created process id or child pid is 166630

Un processus peut se terminer de l'une des deux manières:

  • Anormalement, se produit lors de la livraison de certains signaux, par exemple un signal de fin.

  • Normalement, en utilisant l'appel système _exit () (ou l'appel système _Exit ()) ou la fonction de bibliothèque exit ().

La différence entre _exit () et exit () est principalement l'activité de nettoyage. leexit() effectue un certain nettoyage avant de renvoyer le contrôle au noyau, tandis que le _exit() (ou _Exit ()) renverrait immédiatement le contrôle au noyau.

Considérez l'exemple de programme suivant avec exit ().

Nom de fichier: atexit_sample.c

#include <stdio.h>
#include <stdlib.h>

void exitfunc() {
   printf("Called cleanup function - exitfunc()\n");
   return;
}

int main() {
   atexit(exitfunc);
   printf("Hello, World!\n");
   exit (0);
}

Étapes de compilation et d'exécution

Hello, World!
Called cleanup function - exitfunc()

Considérez l'exemple de programme suivant avec _exit ().

Nom de fichier: at_exit_sample.c

#include <stdio.h>
#include <unistd.h>

void exitfunc() {
   printf("Called cleanup function - exitfunc()\n");
   return;
}

int main() {
   atexit(exitfunc);
   printf("Hello, World!\n");
   _exit (0);
}

Étapes de compilation et d'exécution

Hello, World!