Page suivante Page précédente Table des matières

11. Processus

11.1 fork(), wait()

#include <unistd.h>
pid_t fork(void);
pid_t wait(int *status)

La fonction fork() crée un nouveau processus (fils) semblable au processus courant (père). La valeur renvoyée n'est pas la même pour le fils (0) et pour le père (numéro de processus du fils). -1 indique un échec.

La fonction wait() attend qu'un des processus fils soit terminé. Elle renvoie le numéro du fils, et son status (voir exit()) en paramètre passé par adresse.

Attention. Le processus fils hérite des descripteurs ouverts de son père. Il convient que chacun des processus ferme les descripteurs qui ne le concernent pas.

Exemple :


 
  1     /* biproc.c */

  2     /*
  3      * Illustration de fork() et pipe();
  4      * 
  5      * Exemple à deux processus reliés par un tuyau 
  6      - l'un envoie abcdef...z 10 fois dans le tuyau 
  7      - l'autre écrit ce qui lui arrive du tuyau sur la
  8      sortie standard, en le formattant.
  9      */

 10     #include <unistd.h>
 11     #include <stdlib.h>
 12     #include <stdio.h>
 13     #include <sys/types.h>
 14     #include <sys/wait.h>

 15     #define MAXLIGNE 30

 16     void genere(int sortie)
 17     {
 18             char alphabet[26];
 19             int k;

 20             for (k = 0; k < 26; k++)
 21                     alphabet[k] = 'a' + k;

 22             for (k = 0; k < 10; k++)
 23                     if (write(sortie, alphabet, 26) != 26) {
 24                             perror("write");
 25                             exit(EXIT_FAILURE);
 26                     };
 27             close(sortie);
 28     }

 29     int lire(int fd, char *buf, size_t count)
 30     {
 31             /* lecture, en insistant pour remplir le buffer */
 32             int deja_lus = 0, n;

 33             while (deja_lus < count) {
 34                     n = read(fd, buf + deja_lus, count - deja_lus);
 35                     if (n == -1)
 36                             return (-1);
 37                     if (n == 0)
 38                             break;  /* plus rien à lire */
 39                     deja_lus += n;
 40             };
 41             return (deja_lus);
 42     }

 43     void affiche(int entree)
 44     {
 45             char ligne[MAXLIGNE + 1];
 46             int nb, numligne = 1;

 47             while ((nb = lire(entree, ligne, MAXLIGNE)) > 0) {
 48                     ligne[nb] = '\0';
 49                     printf("%3d %s\n", numligne++, ligne);
 50             };
 51             if (nb < 0) {
 52                     perror("read");
 53                     exit(EXIT_FAILURE);
 54             }
 55             close(entree);
 56     }

 57     int main(void)
 58     {
 59             int fd[2], status;
 60             pid_t fils;

 61             if (pipe(fd) != 0) {
 62                     perror("pipe");
 63                     exit(EXIT_FAILURE);
 64             }
 65             if ((fils = fork()) < 0) {
 66                     perror("fork");
 67                     exit(EXIT_FAILURE);
 68             }

 69             if (fils == 0) {        /* le processus fils */
 70                     close(fd[0]);
 71                     close(1);
 72                     genere(fd[1]);
 73                     exit(EXIT_SUCCESS);
 74             };

 75             /* le processus père continue ici */
 76             close(0);
 77             close(fd[1]);
 78             affiche(fd[0]);
 79             wait(&status);
 80             printf("status fils = %d\n", status);
 81             exit(EXIT_SUCCESS);
 82     }
 

Exercice : Observez ce qui se passe si, dans la fonction affiche(), on remplace l'appel à lire() par un read() ? Et si on ne fait pas le wait() ?

11.2 waitpid()

La fonction waitpid() permet d'attendre l'arrêt d'un des processus fils désigné par son pid (n'importe lequel si pid=-1), et de récupérer éventuellement son code de retour. Elle retourne le numéro du processus fils.

L'option WNOHANG rend waitpid non bloquant (qui retourne alors -1 si le processus attendu n'est pas terminé).

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

pid_t  waitpid (pid_t pid, int *status, int options);

Exemple :

int pid_fils;
int status;

if( (pid_fils = fork()) != 0) {
   code_processus_fils();
   exit(EXIT_SUCCESS);
   };
...
if (waitpid(pid_fils,NULL,WMNOHANG) == -1)
   printf("Le processus fils n'est pas encore terminé\n");
...

11.3 exec()

#include <unistd.h>
int execv (const char *FILENAME, char *const ARGV[])
int execl (const char *FILENAME, const char *ARG0,...)
int execve(const char *FILENAME, char *const ARGV[], char *const ENV[])
int execle(const char *FILENAME, const char *ARG0,...char *const ENV[])
int execvp(const char *FILENAME, char *const ARGV[])
int execlp(const char *FILENAME, const char *ARG0, ...)

Ces fonctions font toutes la même chose : activer un exécutable à la place du processus courant. Elles diffèrent par la manière d'indiquer les paramètres.

11.4 Numéros de processus : getpid(), getppid()

#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);

getpid() permet à un processus de connaître son propre numéro, et getppid() celui de son père.

11.5 Programmation d'un démon

Les démons

Traduction de l'anglais daemon, acronyme de « Disk And Extension MONitor », qui désignait une des parties résidentes d'un des premiers systèmes d'exploitation.
sont des processus qui tournent normalement en arrière-plan pour assurer un service. Pour programmer correctement un démon, il ne suffit pas de faire un fork(), il faut aussi s'assurer que le processus restant ne bloque pas de ressources. Par exemple il doit libérer le terminal de contrôle du processus, revenir à la racine, faute de quoi il empêchera le démontage éventuel du système de fichiers à partir duquel il a été lancé.


 
  1     /* demon.c */

  2     int devenir_demon(void)
  3     {
  4             int fd;

  5             /* Le processus se dédouble, et le père se termine */
  6             if (fork() != 0)
  7                     exit(EXIT_SUCCESS);

  8             /* le processus fils devient le leader d'un nouveau
  9                groupe de processus */
 10             setsid();

 11             /* le processus fils crée le processus démon, et 
 12                se termine */
 13             if (fork() != 0)
 14                     exit(EXIT_SUCCESS);

 15             /* le démon déménage vers la racine */
 16             chdir("/");

 17             /* l'entrée standard est redirigée vers /dev/null */
 18             fd = open("/dev/null", O_RDWR);
 19             dup2(fd, 0);
 20             close(fd);

 21             /* et les sorties vers /dev/console */
 22             fd = open("/dev/console", O_WRONLY);
 23             dup2(fd, 1);
 24             dup2(fd, 2);
 25             close(fd);
 26     }
 

Voir FAQ Unix : 1.7 How do I get my program to act like a daemon


Page suivante Page précédente Table des matières