fork, wait, exec.

Tubes (pipes, en anglais)

Un tube est un mécanisme de communication unidirectionnel permettant le transfert d'un flot continu de caractères. Il est géré comme une file FIFO : les caractères sont lus dans l'ordre dans lequel ils ont été écrits dans le tube.

Le but de ce TP est d'étudier les fonctions fork, wait et exec et d'étudier la communication inter-processus par tubes (en langage C).

L'élève curieux pourra également se reporter au TP analogue proposé en 2007 par Antoine Miné.

Aide

La création d'un tube anonyme se fait à l'aide de la primitive pipe :

#include ‹unistd.h›

int pipe(int p[2]);

qui retourne dans le tableau p passé en paramètre les descripteurs à utiliser pour accéder au tube. p[0] contient le descripteur pour la lecture et p[1] celui pour l'écriture.
La fonction retourne en entier, 0 si la fonction a réussi, -1 sinon. Dans ce cas, la variable errno indique l’erreur :

  • EMFILE : trop de descripteur sont actifs.
  • ENFILE : la table du système de fichiers est pleine.
  • EFAULT : les descripteurs de fichiers sont dans une zone non gérée par le processus.


La lecture se fait grâce à la primitive read dont la syntaxe est

int read(int p[0],void * buf, int nb_car);

nb_car étant le nombre de caractères que l'on souhaite lire à partir du tube et buf un pointeur sur une zone mémoire dans laquelle ils seront rangés après lecture. Cette primitive retourne le nombre de caractères effectivement lus.


L'écriture dans un tube se fait à l'aide de la primitive write dont la syntaxe est

write(int p[1],void * buf, int nb_car);

nb_car est le nombre de caractères que l'on souhaite écrire dans le tube et buf un pointeur sur la zone contenant les caractères à écrire.

top

Exercice 1 - find parallèle

Écrire une commande find_parallele telle que find_parallele fic rep effectue la recherche d'un fichier de nom fic dans le répertoire rep.

Pour cela, chaque processus parcourt le contenu du répertoire dont la référence lui est fournie ; s'il trouve un fichier de nom fic, il en affiche la référence complète ; et pour chaque sous-répertoire, il crée un processus fils chargé d'y poursuivre la recherche.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>


char *concat_slash(char *s, char*t) 
{
  char *tmp = malloc(strlen(s) + strlen(t) + 2);
  strcpy(tmp, s);
  strcat(tmp, "/");
  strcat(tmp, t);
  return tmp;
}

void usage(char *nomcommande)
{
  printf("Usage : %s fic rep\n",nomcommande);
  printf("Recherche de fic dans rep.\n");
  exit(EXIT_FAILURE);
}


int main(int argc, char **argv) 
{
   if (argc!=3)
    usage(argv[0]);
  
  DIR * dir;
  struct dirent * entry;
  int nbfils = 0;
  char *tmp;
  struct stat st;
  
  dir = opendir(argv[2]);
  while ((entry = readdir(dir))) 
    {
      if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) 
	{
	  tmp = concat_slash(argv[2], entry->d_name);
	  stat(tmp, &st);
	  if (S_ISDIR(st.st_mode))
	    switch (fork()) {
	    case -1 : 
	      perror("");
	      fprintf(stderr, "Recherche ds %s non effectuee\n", tmp);
	      break;
	    case 0 :  
	      printf("Lancement de %d sur %s\n", getpid(), tmp);
	      argv[2] = tmp; 
	      execvp(argv[0], argv); 
	      break;
	    default : 
	      nbfils++;
	    }
	  else if (!strcmp(entry->d_name, argv[1]))
	    printf("%d a trouve %s\n",getpid(), tmp);
	  free(tmp);
	}
    }
  
  while (nbfils --)  wait(NULL);
  
  exit(EXIT_SUCCESS);
}
top

Exercice 2 - Recherche parallélisée dans un tableau

On souhaite trouver toutes les occurrences d'un élément dans un tableau donné. Pour cela, si le tableau est long (plus qu'une constante TAILLE_MIN), on peut le couper en deux et effectuer la recherche indépendamment dans les deux moitiés, en les confiant à deux processus différents travaillant en parallèle.

Écrire un programme effectuant la recherche de cette manière ; le programme devra afficher un message pour chaque occurrence trouvée, puis afficher le nombre total d'occurrences de l'élément dans le tableau. Pour cela, on pourra utiliser les valeurs de retour des processus fils (ces valeurs de retour sont codées sur un octet).

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

#define MIN 3

char recherche(int *tab, int val, int deb, int fin) 
{
  char res = (char)0;
  int pid_fils, stat, i;
  if (fin - deb <= MIN) 
    {
      for (i = deb; i < fin; i++)
	if (tab[i] == val) 
	  {
	    printf("%d : %d en position %d\n", getpid(), val, i);
	    res ++;
	  }
      return res;
    }
  else 
    switch (pid_fils = fork()) 
      {
      case -1 :
	perror("fork");
	fprintf(stderr, "Plage [%d,%d[ avortee\n", (deb+fin)/2, fin);
	exit(0);
      case 0 : 
	exit(recherche(tab, val, (deb+fin)/2, fin));
      default :
	res = recherche(tab, val, deb, (deb+fin)/2);
	waitpid(pid_fils, &stat, 0);
	return res + WEXITSTATUS(stat);
      }
}

int main() 
{
  int n = 16, val = 5, i;
  int tab[] = {0,5,6,2,3,5,7,5,9,8,5,4,1,3,2,5};
  
  printf("Recherche de %d dans le tableau : \n\t", val);
  for (i=0; i < n; i++) printf("%d ", tab[i]);
  printf("\n");
  
  if ((i = recherche(tab,val,0,n)) > 0)
    printf("%d occurrences trouvees\n",i);
  else
    printf("element non trouve\n");

  exit(EXIT_SUCCESS);
}
top

Exercice 3 - Communication inter-processus

Écrire un programme C qui crée deux processus communiquant par tube de communication. Le processus producteur ouvre un fichier donné en argument du programme et transmet le contenu de ce fichier au processus consommateur via un tube de communication. Ce processus écrit le contenu du tube dans le deuxième fichier passé en argument.

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

#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>

#define BUFSZ 1024


void copy(int in, int out, void *buf, int sz)
{  
  while (write(out, buf, read(in, buf, sz)));
}



int main(int argc, char **argv)
{  
  int p[2], fd;
  
  pid_t pid;
  static char buf[BUFSZ];
  
  if (argc != 3)
    {  
      fprintf(stderr, "Usage : %s fichier1 fichier2\n", argv[0]);
      exit(1);
   }
  if (pipe(p))
    { 
      perror("pipe"); exit(1);
    }
  
  if ((pid = fork()) == -1)
    { 
      perror("fork"); exit(1);
    }
  
  if (pid)
    { 
      close(p[0]);
      if ((fd = open(argv[1], O_RDONLY)) == -1)
	{  
	  perror("open"); kill(pid, SIGKILL); exit(1);
	}
      
      copy(fd, p[1], buf, BUFSZ);
      
      close(p[1]);
      close(fd);
      wait(NULL);
    }
  
  else
    {
      close(p[1]);
      if ((fd = creat(argv[2], 0664)) == -1)
	{  
	  perror("open"); kill(getppid(), SIGKILL); exit(1);
	}
      
      copy(p[0], fd, buf, BUFSZ);
      
      close(p[0]);
      close(fd);
    }
  return 0;
}
top

Exercice 4 - ls -al | wc -l

Écrire un programme C qui réalise la commande ls -al | wc -l en créant deux processus qui communiquent à travers un tube. Le fils écrit dans le tube en ayant au préalable redirigé sa sortie standard à travers un tube ; quant au père il lit dans le tube en ayant au préalable redirigé son entrée standard vers le tube.

Pour la redirection de la sortie et de l'entrée standard, utiliser la fonction dup.
Utiliser la primitive de recouvrement execlp pour faire exécuter au fils et au père les commandes ls et wc.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv) 
{
  int pid;
  int p[2];
  
  if (pipe(p) < 0) 
    {
      perror("pb creation pipe");
      exit(1);
    }

  pid = fork();

  if (pid == 0) 
    {

      // le fils fait wc -l
      close(p[1]);
      close(STDIN_FILENO);
      dup(p[0]);
      close(p[0]);
     
      execlp("/usr/bin/wc","wc","-l",(char *)NULL);
      
      printf("pb exec wc -l");
      exit(1);
    }
   
  else if (pid > 0) 
    {
      
      // le père fait ls -al
      close(p[0]);
      close(STDOUT_FILENO);
      dup(p[1]);
      close(p[1]);
      
      execlp("/bin/ls","ls","-al",(char *)NULL);
      
      printf("pb exec ls -al");
      exit(1);
      
    }
  else 
    {
      perror("pb creation fils");
      exit(1);
    }
  
  exit(0);
}
top

Exercice 5 - Crible d'Eratosthene

Le but de cet exercice est d'implanter le crible d'Erathosthene comme test de primalité d'un entier rationnel (il existe bien évidemment des tests de primalité plus efficaces).

  1. En divisant la liste de facteurs premiers dans des ensembles de cardinal au plus huit et en utilisant fork, exit et wait, distribuer le test de divisibilité du nombre premier candidat par chacun de ces facteurs premiers.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <string.h>
    #include <math.h>
    #include <sys/types.h>
    
    #define CAND_MAX 12000	
    #define TAILLE_SEQ 8
    
    void Usage (char *progname) 
    {
      fprintf (stderr, "Usage : %s candidat\n", progname);
      fprintf (stderr, "\tcandidat inferieur a %d !\n", CAND_MAX);
      exit(-1);
    }
    
    int Eratosthenes (int n, int **ppremiers) 
    {
      int i, j;
      char *crible;
      int *premiers;
      int nonpremiers;
      
      crible = (char *)calloc(n+1, sizeof(char));
      if (crible == NULL) 
        {
          perror ("calloc de crible");
          exit(-1);
        }
      
    
      nonpremiers = 1;
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) 
    	{
    	  for (j = 2*i; j <= n; j+=i) 
    	    {
    	      if (!crible[j]) 
    		{
    		  crible[j] = 1;
    		  nonpremiers++;
    		}
    	    }
    	}
        }
      
      *ppremiers = premiers = (int *)calloc((n - nonpremiers + 1), 
                                       sizeof(int));
      if (premiers == NULL) 
        {
          perror ("calloc de premiers");
          exit(-1);
        }
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) {
    	*premiers++ = i;
          }
        }
      
      free ((void *)crible);
      
      return (n - nonpremiers);
    }
    
    
    int FacteursPremiers 
    (unsigned long candidat, int sequence, int *prime) 
    {
      int i, p;
      int diviseurs_premiers = 0;
      
      for (i = 0; i < TAILLE_SEQ; i++) 
        {
          p = sequence * TAILLE_SEQ + i;
          
          if (!prime[p])
    	exit(diviseurs_premiers);
          
          else if (!(candidat % prime[p])) {
    	diviseurs_premiers = 1;
          }
        }
      
      exit(diviseurs_premiers);
    }
    
    int main(int argc, char *argv[]) 
    {
      int *premiers;
      int nbr_premiers;
      int nbr_fils;
      pid_t *fils_pid;
      pid_t pid_fini;
      int i;
      int statut;
      int resultat;
      int intervalle;	
      unsigned long candidat;
      int facteurs;		
    
      if (argc != 2)
        Usage(argv[0]);
      
      candidat = atol(argv[1]);
      if (candidat < 2 || candidat > CAND_MAX) 
        Usage(argv[0]);
    
      intervalle = (int)sqrt(candidat);
    
      nbr_premiers = Eratosthenes(intervalle, &premiers);
      printf ("Creation d'une liste de %d premiers\n", nbr_premiers);
    
      nbr_fils = (int) ceil ((double) nbr_premiers/TAILLE_SEQ);
      printf ("Division du calcul en %d processus\n", nbr_fils);
    
      fils_pid = (pid_t *)calloc(nbr_fils, sizeof(pid_t));
      if (fils_pid == NULL) {
        perror ("calloc de fils_pid");
        exit(-1);
      }
      
      for (i = 0; i < nbr_fils; i++) {
        fils_pid[i] = fork();
        switch (fils_pid[i]) {
        case -1:
          perror ("fork");
          exit(1);
          break;
        case 0:
          FacteursPremiers(candidat, i, premiers);
          break;
        default:
          ;
        }
      }
    
      facteurs = 0;
      
      for (i = 0; i < nbr_fils; i++) 
        {
          pid_fini = wait (&statut);
          resultat = statut;
          if (!resultat)
    	continue;
          else 
    	facteurs=1;
    
        }
      
      if (!facteurs)
        printf ("\n%lu est premier\n", candidat);
      else 
        printf ("%lu n'est pas premier\n", candidat);
      
      return 0;
    }
    

  2. Modifier votre programme pour que le processus initial retourne tous les facteurs premiers trouvés (sans utiliser de tube).
    (Indice : exit retourne une valeur au processus parent).

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <string.h>
    #include <math.h>
    #include <sys/types.h>
    
    #define CAND_MAX 12000	
    #define TAILLE_SEQ 8
    
    void Usage (char *progname) 
    {
      fprintf (stderr, "Usage : %s candidat\n", progname);
      fprintf (stderr, "\tcandidat inferieur a %d !\n", CAND_MAX);
      exit(-1);
    }
    
    int Eratosthenes (int n, int **ppremiers) 
    {
      int i, j;
      char *crible;
      int *premiers;
      int nonpremiers;
      
      crible = (char *)calloc(n+1, sizeof(char));
      if (crible == NULL) 
        {
          perror ("calloc de crible");
          exit(-1);
        }
      
    
      nonpremiers = 1;
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) 
    	{
    	  for (j = 2*i; j <= n; j+=i) 
    	    {
    	      if (!crible[j]) 
    		{
    		  crible[j] = 1;
    		  nonpremiers++;
    		}
    	    }
    	}
        }
      
      *ppremiers = premiers = (int *)calloc((n - nonpremiers + 1), 
                                       sizeof(int));
      if (premiers == NULL) 
        {
          perror ("calloc de premiers");
          exit(-1);
        }
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) {
    	*premiers++ = i;
          }
        }
      
      free ((void *)crible);
      
      return (n - nonpremiers);
    }
    
    
    int FacteursPremiers 
    (unsigned long candidat, int sequence, int *prime) 
    {
      int i, p;
      int prime_divisors = 0;
      
      for (i = 0; i < TAILLE_SEQ; i++) 
        {
          p = sequence * TAILLE_SEQ + i;
          
          if (!prime[p])
    	exit(prime_divisors);
          
          else if (!(candidat % prime[p])) {
    	prime_divisors |= (1 << i);
          }
        }
      
      exit(prime_divisors);
    }
    
    int main(int argc, char *argv[]) 
    {
      int *premiers;
      int nbr_premiers;
      int nbr_fils;
      pid_t *fils_pid;
      pid_t pid_fini;
      int i, j, k;
      int p;
      int statut;
      int resultat;
      int intervalle;	
      unsigned long candidat;
      int facteurs;		
    
      if (argc != 2)
        Usage(argv[0]);
      
      candidat = atol(argv[1]);
      if (candidat < 2 || candidat > CAND_MAX) 
        Usage(argv[0]);
    
      intervalle = candidat/2;
    
      nbr_premiers = Eratosthenes(intervalle, &premiers);
      printf ("Creation d'une liste de %d premiers\n", nbr_premiers);
    
      nbr_fils = 1+nbr_premiers/TAILLE_SEQ;
      printf ("Division du calcul en %d processus\n", nbr_fils);
    
      fils_pid = (pid_t *)calloc(nbr_fils, sizeof(pid_t));
      if (fils_pid == NULL) {
        perror ("calloc de fils_pid");
        exit(-1);
      }
      
      for (i = 0; i < nbr_fils; i++) {
        fils_pid[i] = fork();
        switch (fils_pid[i]) {
        case -1:
          perror ("fork");
          exit(1);
          break;
        case 0:
          FacteursPremiers(candidat, i, premiers);
          break;
        default:
          ;
        }
      }
    
      facteurs = 0;
      
      for (i = 0; i < nbr_fils; i++) 
        {
          pid_fini = wait (&statut);
          
          resultat = (statut & 0xff00) >> 8;
    
          if (!resultat)
    	continue;
          
          if (!facteurs)
    	printf ("\n");
          
          for (j = 0; j < nbr_fils; j++) {
    	if (pid_fini == fils_pid[j]) {
    	  for (k = 0; k < TAILLE_SEQ; k++) {
    	    if (resultat & (1 << k)) 
    	      {
    		facteurs++;
    		p = j * TAILLE_SEQ + k;
    		printf ("%d\n", premiers[p]);
    	      }
    	  }
    	  break;
    	}
          }
        }
      
      if (!facteurs)
        printf ("\n%lu est premier\n", candidat);
      else 
        printf ("%lu n'est pas premier\n", candidat);
      
      return 0;
    }
    

  3. Dans cette question, le processus fera parvenir les facteurs premiers trouvés (le cas échéant) au processus père en utilisant les canaux de communication fournis par un tube

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <math.h>
    
    #define CAND_MAX 33000
    #define TAILLE_SEQ 20	
    #define LONG_LIG 50
    
    typedef struct 
    {
      pid_t pid;
      int fildes[2];
      int sequence;
    } process_t;
    
    
    void Usage (char *progname) 
    {
      fprintf (stderr, "Usage : %s candidat\n", progname);
      fprintf (stderr, "\tcandidat inferieur a %d !\n", CAND_MAX);
      exit(-1);
    }
    
    
    int Eratosthenes (int n, int **ppremiers) 
    {
      int i, j;
      char *crible;
      int *premiers;
      int nonpremiers;
      
      crible = (char *)calloc(n+1, sizeof(char));
      if (crible == NULL) 
        {
          perror ("calloc de crible");
          exit(-1);
        }
      
    
      nonpremiers = 1;
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) 
    	{
    	  for (j = 2*i; j <= n; j+=i) 
    	    {
    	      if (!crible[j]) 
    		{
    		  crible[j] = 1;
    		  nonpremiers++;
    		}
    	    }
    	}
        }
      
      *ppremiers = premiers = (int *)calloc((n - nonpremiers + 1),
                                          sizeof(int));
      if (premiers == NULL) 
        {
          perror ("calloc de premiers");
          exit(-1);
        }
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) {
    	*premiers++ = i;
          }
        }
      
      free ((void *)crible);
      
      return (n - nonpremiers);
    }
    
    
    int FacteursPremiers 
    (process_t *w, unsigned long candidat, int *premier) 
    {
      int i, p;
      char msg[LONG_LIG];
      int nbr_octets;
      
      for (i = 0; i < TAILLE_SEQ; i++) 
        {
          p = w->sequence * TAILLE_SEQ + i;
          
          if (!premier[p])
    	exit(0);
          else if (!(candidat % premier[p])) 
    	{
    	  sprintf (msg, "%d\n", premier[p]);
    	  nbr_octets = write (w->fildes[1], (void *)msg, 
                              strlen(msg));
    	  if (nbr_octets != strlen(msg)) 
    	    {
    	      perror ("write");
    	      exit(-1);
    	    }
    	}
        }
      
      exit(0);
    }
    
    int main(int argc, char *argv[]) 
    {
      int *premiers;
      int nbr_premiers;
      int nbr_fils;
      process_t *processus;
      int i;
      int nbr_octets;
      int intervalle;
      unsigned long candidat;
      int facteurs;	
      char buf[LONG_LIG];
      char *str;	
      
      if (argc != 2)
        Usage(argv[0]);
      
      candidat = atol(argv[1]);
      if (candidat < 2 || candidat > CAND_MAX) 
        Usage(argv[0]);
      
      intervalle = candidat/2;
      
      nbr_premiers = Eratosthenes(intervalle, &premiers);
      printf ("Creation d'une liste de %d premiers\n", nbr_premiers);
      
      nbr_fils = (int) ceil((double) nbr_premiers/TAILLE_SEQ);
      printf ("Division du calcul en %d processus\n", nbr_fils);
      
      processus = (process_t *)calloc(nbr_fils, sizeof(process_t));
      if (processus == NULL) 
        {
          perror ("calloc of processus");
          exit(-1);
        }
      
      for (i = 0; i < nbr_fils; i++) {
        processus[i].sequence = i;
        pipe(processus[i].fildes);
        processus[i].pid = fork();
        switch (processus[i].pid) {
        case -1:
          perror ("fork");
          exit(1);
          break;
        case 0:
          close (processus[i].fildes[0]);
          FacteursPremiers(&(processus[i]), candidat, premiers);
          break;
        default:
          close (processus[i].fildes[1]);
        }
    	}
      
      facteurs = 0;	
      
      for (i = 0; i < nbr_fils; i++) 
        {
          nbr_octets = read (processus[i].fildes[0], 
    			 (void *)buf, 
    			 (size_t)LONG_LIG);
          
          if (nbr_octets < 0) 
    	{
    	  perror("read");
    	  exit(-1);
    	}
          
          buf[nbr_octets] = '\0';
        
          str = strtok (buf, "\n");
          
          while (str) 
    	{
    	  if (!facteurs)
    	    printf ("\n");
    	  facteurs++;
    	  printf ("%s\n", str);
    	  
    	  str = strtok (NULL, "\n");
    	}
      }
      
      if (!facteurs)
        printf ("\n%lu est premier\n", candidat);
      else 
        printf ("\n%lu n'est pas premier\n", candidat);
      
      return 0;
    }
    

  4. Pour un problème de calcul distribué plus réaliste, la complexité des processus peut prendre plus de quelques millisecondes.
    Dans un tel cas, le processus père ne doit pas attendre les résultats d'un calcul lent lorsque d'autres résultats sont prêts.

    Utiliser la fonction select afin que les résultats soient lus dès qu'ils sont disponibles. Chaque processus devrait faire savoir au processus père quand il a fini son travail afin celui-ci puisse fermer le tube correspondant.
    Introduire une durée de cinq secondes de retard dans le processus de traitement de la première série de nombres premiers et vérifier que le programme ne bloque pas dans l'attente de la première série de résultats.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/wait.h>
    #include <math.h>
    
    #define CAND_MAX 33000	
    #define TAILLE_SEQ 20	
    #define LONG_LIG 50	
    #define CH_FIN "fin"	
    
    typedef struct {
      pid_t pid;
      int fildes[2];
      int sequence;
    } process_t;
    
    void Usage (char *progname) {
      fprintf (stderr, "Usage : %s candidat\n", progname);
      fprintf (stderr, "\tcandidat inferieur a %d !\n", CAND_MAX);
      exit(-1);
    }
    
    
    int Eratosthenes (int n, int **ppremiers) 
    {
      int i, j;
      char *crible;
      int *premiers;
      int nonpremiers;
      
      crible = (char *)calloc(n+1, sizeof(char));
      if (crible == NULL) 
        {
          perror ("calloc de crible");
          exit(-1);
        }
      
    
      nonpremiers = 1;
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) 
    	{
    	  for (j = 2*i; j <= n; j+=i) 
    	    {
    	      if (!crible[j]) 
    		{
    		  crible[j] = 1;
    		  nonpremiers++;
    		}
    	    }
    	}
        }
      
      *ppremiers = premiers = (int *)calloc((n - nonpremiers + 1), 
                                         sizeof(int));
      if (premiers == NULL) 
        {
          perror ("calloc de premiers");
          exit(-1);
        }
      
      for (i = 2; i <= n; i++) 
        {
          if (!crible[i]) {
    	*premiers++ = i;
          }
        }
      
      free ((void *)crible);
      
      return (n - nonpremiers);
    }
    
    
    
    int FacteursPremiers 
    (process_t *w, unsigned long candidat, int *premier, int nump) 
    {
      int i, p;
      char msg[LONG_LIG];
      int nbr_octets;
      
      if (w->sequence == 0)
        sleep(5);
      
      for (i = 0; i < TAILLE_SEQ; i++) 
        {
          p = w->sequence * TAILLE_SEQ + i;
          
          if (p < nump && ! (candidat % premier[p])) 
    	{
    	  sprintf (msg, "%d\n", premier[p]);
    	  nbr_octets = write (w->fildes[1], 
                       (void *)msg, strlen(msg));
    	  if (nbr_octets != strlen(msg)) {
    	    perror ("write");
    	    exit(-1);
    	  }
    	}
        }
      
      strcpy (msg, CH_FIN);
      nbr_octets = write (w->fildes[1], (void *)msg, strlen(msg));
      if (nbr_octets != strlen(msg)) 
        {
          perror ("write");
          exit(-1);
        }
      
      close (w->fildes[1]);
      
      exit(0);
    }
    
    
    int main(int argc, char *argv[]) 
    {
      int *premiers;
      int nbr_premiers;
      int nbr_fils;
      int nbr_fils_actifs;
      process_t *processus;
      int i;
      int statut;
      int nbr_octets;
      int intervalle;
      unsigned long candidat;
      int facteurs;	
      fd_set r;
      struct timeval timeout;
      char buf[LONG_LIG];
      char *str;
      
      if (argc != 2)
        Usage(argv[0]);
      
      candidat = atol(argv[1]);
      if (candidat < 2 || candidat > CAND_MAX) 
        Usage(argv[0]);
    
      intervalle = candidat/2;
      
      nbr_premiers = Eratosthenes(intervalle, &premiers);
      printf ("Creation d'une liste de %d premiers\n", nbr_premiers);
    
      nbr_fils = 1+nbr_premiers/TAILLE_SEQ;
      nbr_fils_actifs = 0;
      printf ("Division du calcul en %d processus\n", nbr_fils);
    
      processus = (process_t *)calloc(nbr_fils, sizeof(process_t));
      if (processus == NULL) {
        perror ("calloc de processus");
        exit(-1);
      }
    
      for (i = 0; i < nbr_fils; i++) 
        {
          processus[i].sequence = i;
          pipe(processus[i].fildes);
          processus[i].pid = fork();
          switch (processus[i].pid) 
    	{
    	case -1:
    	  perror ("fork");
    	  exit(1);
    	  break;
    	case 0:
    	  close (processus[i].fildes[0]);
    	  FacteursPremiers(&(processus[i]), candidat, 
    			   premiers, nbr_premiers);
    	  break;
    	default:
    	  close (processus[i].fildes[1]);
    	  nbr_fils_actifs++;
    	}
          
        }
      
      facteurs = 0;
    
      timeout.tv_sec = 1;
      timeout.tv_usec = 0;
    
      while (nbr_fils_actifs) 
        {
          FD_ZERO(&r);
          for (i = 0; i < nbr_fils; i++) 
    	{
    	  if (processus[i].pid) {
    	    FD_SET(processus[i].fildes[0], &r);
    	  }
    	}
          
          if (select(FD_SETSIZE, &r, NULL, NULL, &timeout) == 0) 
    	{
    	  continue;
    	}
    
          for (i = 0; i < nbr_fils; i++) 
    	{
    	  if (FD_ISSET (processus[i].fildes[0], &r)) 
    	    {
    	      nbr_octets = read (processus[i].fildes[0], 
    				 (void *)buf, 
    				 (size_t)LONG_LIG);
    	      
    	      if (nbr_octets < 0) {
    		perror("read");
    		exit(-1);
    	      }
    	      
    	      buf[nbr_octets] = '\0';
    	      
    	      str = strtok (buf, "\n");
    
    	      while (str) 
    		{
    		  if (!strcmp (str, CH_FIN)) {
    		    close (processus[i].fildes[0]);
    		    waitpid(processus[i].pid, 
    			    &statut, 0);
    		    processus[i].pid = 0;
    		    nbr_fils_actifs--;
    		  }
    
    		  
    		  else {
    		    if (!facteurs)
    		      printf ("\n");
    		    facteurs++;
    		    printf ("%s\n", str);
    		  }
    		  
    		  str = strtok (NULL, "\n");
    		}
    	    }
    	}
        }
      
      if (!facteurs)
        printf ("\n%lu est premier\n", candidat);
      else
        printf ("\n%lu n'est pas premier\n", candidat);
      
      return 0;
    }
    

    1. top