Précédent Index Suivant

6.4   fork

fork duplique une vie. C'est un clonage ! Une tâche qui invoque fork crée par scissiparité une seconde tâche en tout point semblable à elle-même, à un unique détail près ! fork retourne à la mère le numéro de la tâche fille engendrée mais ne retourne que zéro à la fille qui ignore donc, véritable orpheline, qui est sa mère ! Les deux tâches continuent alors leur exécution en séquence après l'appel à fork(),et en parallèle entre elles. Pour rester dans le domaine féérique, fork est analogue au coup de hache que donne l'apprenti sorcier [Goethe] au balai récalcitrant. Il ne fait qu'obtenir deux balais rigoureusement identiques et programmés pour le même travail.

fork est le seul moyen de créer une tâche. L'aïeule commune à toutes est init créée ex nihilo au lancement du système. Pour lancer une tâche sur un programme on utilise un fork suivi d'un exec. Comme ce qui suit :
#define ERREUR_FORK -1
fille=fork();            /* fourcher !   */
/* Il y a maintenant deux tâches qui 
   exécutent ce qui suit                */
if ( fille != ERREUR_FORK )
   /* le clonage s'est bien déroulé !   */
   if ( fille == 0 )
      /* Seule la fille exécute ce qui suit     */
      execl("programme", ... arguments ...);
      /* et elle continuera par la première 
         instruction de programme           */
   /* Par contre ici ne peut passer que la tâche mère 
      qui imprime le numéro de sa fille (en décimal) */
   printf(" ma fille est : %d",fille);
   ... suite ...  

Au niveau de l'interprète de commandes, existent & et exec qui mettent en jeu les mêmes mécanismes. Donnons un exemple plus réel montrant l'énorme consommation de tâches de sh. Soit le fichier exécutable cycle contenant :
programme &
{ sleep $1
  kill -9 $?
  exec cycle `expr $1 + 10`
  }  
et soit sh<1> (tous les noms de tâches seront indicées par le numéro de tâche associée afin que l'on puisse suivre ces mêmes tâches se transmutant et différencier celles qui ont un même programme support.) l'interprète de commandes auquel vous soumettez
 cycle 10 


sh<1> voit que cycle est un programme à lancer aussi fourche-t'il (créant ainsi sh<2>), sh<2> analyse cycle, et sh<1> se met en attente de la fin de sh<2>.


sh<2> substitue textuellement $1 en 10 dans tout cycle puis remarquant la présence d'un &, fourche en sh<3> qui analyse programme tandis que, sans attendre, sh<2> poursuit l'analyse du reste de cycle.


sh<3> n'étant qu'un simple programme à lancer, se transmue en programme grâce à exec.


Pendant ce temps sh<2> substitue à $? le numéro de tâche de sh<3> (qui est aussi celui de programme<3> après l'exec), constate que c'est une séquence d'appels, fourche donc, en conséquence et en sh<4>, destiné à analyser
 sleep 10 
tandis que sh<2> diffère l'examen de
kill -9 sh<3>
exec cycle `expr 10 + 10`  
en attendant la fin de sh<4>.


sh<4> execute sleep, attend 10 secondes puis meurt, relançant ainsi sh<2> qui poursuit son analyse, constate que c'est une séquence et fourche donc derechef.


sh<5> examine kill -9sh<3>, execute kill, envoie donc le signal 9 (SIGKILL) à programme<3> et donc le tue radicalement, sans autre forme de procès.


Son office achevé sh<5> meurt. sh<2>, qui n'attendait que cela, scrute la ligne
 exec cycle `expr 10 + 10` 
Cette commande nécessite de calculer
 expr 10 + 10 
aussi, encore une nouvelle fois, sh<2> fourche-t'il en sh<6> qui executeexpr.


Ce dernier, après décodage de ses arguments, place 20 sur son flux sortant, récupéré par sh<2> qui n'a plus à interpréter que
 exec cycle 20 


sh<2> se transmue alors en cycle qui est un texte exécutable à interpréter, aussi se transmue-t'il à nouveau en sh, et tout recommence !!!


cycle permet tout bonnement d'exécuter un programme pendant des durées de plus en plus longues.
Précédent Index Suivant