2017-03-12 2 views
1

J'ai rencontré des problèmes lors de l'utilisation de tuyaux et de processus enfants.Le tuyau et la fourche entraînent une sortie incorrecte et désordonnée

I doivent

  1. créer quatre fils avec fork()
  2. établir tuyau en utilisant une communication à deux voies() entre le parent et chaque enfant
  3. lire les données d'un certain nombre de fichiers contenant card.txt des chaînes
  4. cordes distribuer de manière ronde à chaque enfant ABCDEFGH, enfant 1 obtenir AE, enfant 2 get BF et ainsi de suite
  5. sélectionner une variable membre -> se nd variable parent à l'aide d'écriture() et lire() et close() pour fermer tuyau utilisé fin
  6. impression reçu variable processus parent

Une sortie attendue est:

$ ./a.out 1C < card.txt 
    Child : 1, pid 1593 : 
    <S2 S3 S9 ><H9 H6 HA H8 ><C6 CK ><D8 DQ D7 D3 > 
    Child : 2, pid 1594 : 
    <SA S6 S7 S4 ><H4 HJ H7 ><CQ C9 CT ><DT D2 D9 > 
    Child : 3, pid 1595 : 
    <SQ S5 ><H2 ><C7 C5 C8 CA C4 CJ C3 ><DA D5 > 
    Child : 4, pid 1596 : 
    <S8 SJ SK ST ><HK HT H5 H3 HQ ><C2 ><D4 D6 > 
    child 1: H9 
    parent: child 1 played H9 
    child 2: CQ 
    parent: child 2 played CQ 
    child 3: H2 
    parent: child 3 played H2 
    child 4: HK 
    parent: child 4 played HK 

Cependant, la sortie réelle est la suivante:

parent: child 1 played (null)parent: child 2 played (null)parent: child 3 played (null)parent: child 4 played (null) 

Pourquoi est-ce? Comment résoudre le problème?

Le code créé cette sortie:

#include <stdio.h> 
#include <string.h> 

#define BUFFERSIZE 51 
int i=0; 
    int currpid, s; 
    char *buf[BUFFERSIZE]; 
    char *array[BUFFERSIZE]; 
    int n; 
    char *buffer[100]; 
/** child to parent pipe */ 
    int child_parent[2]; 
    /** parent to child pipe */ 
    int parent_child[2]; 

    /** child2 to parent pipe */ 
    int child2_parent[2]; 
    /** parent to child2 pipe */ 
    int parent_child2[2]; 

    /** child3 to parent pipe */ 
    int child3_parent[2]; 
    /** parent to child3 pipe */ 
    int parent_child3[2]; 

    /** child4 to parent pipe */ 
    int child4_parent[2]; 
    /** parent to child4 pipe */ 
    int parent_child4[2]; 

void childFunction(){ 
    int j; 
     for(i = s+1; i < BUFFERSIZE; i += 4) 
     { 
      buf[j] = array[i]; 
      j++; 
     } 
     printf("\n<"); 
     int r; 
     char *e; 
     for(r = 0; r < j; r++) 
     { 
      int index; 
      e = strchr(buf[r],'S'); 
      if (e!=NULL){ 
       index = (int)(e-buf[r]); 
       if (index == 0){ 

        printf("%s ", buf[r]) ; 
       } 
      } 
     } 
     printf(">"); 
     printf("<"); 
     for(r = 0; r < j; r++) 
     { 
      int index; 
      e = strchr(buf[r],'H'); 
      if (e!=NULL){ 
       index = (int)(e-buf[r]); 
       if (index == 0){ 
        printf("%s ", buf[r]) ; 
       } 
      } 
     } 
     printf(">"); 
     printf("<"); 
     for(r = 0; r < j; r++) 
     { 
      int index; 
      e = strchr(buf[r],'C'); 
      if (e!=NULL){ 
       index = (int)(e-buf[r]); 
       if (index == 0){ 
        printf("%s ", buf[r]) ; 
       } 
      } 
     } 
     printf(">"); 
     printf("<"); 
     for(r = 0; r < j; r++) 
     { 
      int index; 
      e = strchr(buf[r],'D'); 
      if (e!=NULL){ 
       index = (int)(e-buf[r]); 
       if (index == 0){ 
        printf("%s ", buf[r]) ; 
       } 
      } 
     } 
     printf(">\n"); 
     switch (s){ 
      case 0: 
       close(parent_child[1]); 
       close(parent_child[0]); 
       close(child_parent[0]); 
       buffer[0] = buf[0]; 
       printf("child %d: %s", s+1, buffer[0]); 
       write(child_parent[1], &buffer[0], strlen(buffer[0])); 
       close(child_parent[1]); 
       break; 
      case 1: 
       close(parent_child2[1]); 
       close(parent_child2[0]); 
       close(child2_parent[0]); 
       buffer[0] = buf[0]; 
       printf("child %d: %s", s+1, buffer[0]); 
       write(child2_parent[1], &buffer[0], strlen(buffer[0])); 
       close(child2_parent[1]); 
       break; 
      case 2: 
       close(parent_child3[1]); 
       close(parent_child3[0]); 
       close(child3_parent[0]); 
       buffer[0] = buf[0]; 
       printf("child %d: %s", s+1, buffer[0]); 
       write(child3_parent[1], &buffer[0], strlen(buffer[0])); 
       close(child3_parent[1]); 
       break; 
      case 3: 
       close(parent_child4[1]); 
       close(parent_child4[0]); 
       close(child4_parent[0]); 
       buffer[0] = buf[0]; 
       printf("child %d: %s", s+1, buffer[0]); 
       write(child4_parent[1], &buffer[0], strlen(buffer[0])); 
       close(child4_parent[1]); 
       break; 
     } 
} 
void parentFunction(){ 

       switch (s){ 
        case 0: 
         close(child_parent[1]); 
         close(parent_child[1]); 
         close(parent_child[0]); 
         read(child_parent[0],&buffer[0], sizeof(buffer[0])); 
         printf("parent: child %d played %s", s+1, buffer[0]); 
         close(child_parent[0]); 
         break; 
        case 1: 
         close(child2_parent[1]); 
         close(parent_child2[1]); 
         close(parent_child2[0]); 
         read(child2_parent[0],&buffer[0], sizeof(buffer[0])); 
         printf("parent: child %d played %s", s+1, buffer[0]); 
         close(child2_parent[0]); 
         break; 
        case 2: 
         close(child3_parent[1]); 
         close(parent_child3[1]); 
         close(parent_child3[0]); 
         read(child3_parent[0],&buffer[0], sizeof(buffer[0])); 
         printf("parent: child %d played %s", s+1, buffer[0]); 
         close(child3_parent[0]); 
         break; 
        case 3: 
         close(child4_parent[1]); 
         close(parent_child4[1]); 
         close(parent_child4[0]); 
         read(child4_parent[0],&buffer[0], sizeof(buffer[0])); 
         printf("parent: child %d played %s", s+1, buffer[0]); 
         close(child4_parent[0]); 
         break; 
       } 
} 
int main(int argc, char *argv[]) 
{ 
    int ch; 
    ssize_t rread; 
    char *line = NULL; 
    size_t len = 0; 
    while (rread = getdelim(&line, &len, '\0', stdin) != -1) { 
    } 

    array[i] = strtok(line," "); 

    while(array[i]!=NULL) 
    { 
     array[++i] = strtok(NULL," "); 
    } 

    int childlimit = 4; 
    int childpids[childlimit]; 
    int currpid; 


    if (pipe(child_parent) == 0 && pipe(parent_child) == 0 && pipe(child2_parent) == 0 && pipe(parent_child2) == 0 && pipe(child3_parent) == 0 && pipe(parent_child3) == 0 && pipe(child4_parent) == 0 && pipe(parent_child4) == 0) 
    { 
     for(s=0; s<childlimit; s++){ 
     switch(currpid = fork()){ 
     case 0: 
     printf("Child : %d, pid %d : ", s+1, getpid()); 
     childFunction(); 
     break; 
     case -1: 
     printf("Error when forking\n"); 
     return 1; 
     default: 
     // in the father 
     childpids[s] = currpid; 
     parentFunction(); 
     break; 
     } 
      } 
    //wait for all child created to die 
    waitpid(-1, NULL, 0); 
    } 
} 
+1

Avez-vous entendu parler de ces choses appelées 'fonctions'? Ils sont utiles pour rendre le code plus clair. Il y a beaucoup trop de code pour le traitement de l'enfant dans la fonction principale. Gardez la gestion des processus dans 'main()'; déléguez le traitement de chaîne et les opérations d'E/S à une fonction qui s'exécute uniquement dans les enfants. Vous ne fermez pas assez de descripteurs de fichiers dans les enfants. Vous fermez trop de descripteurs de fichier dans le parent si le parent doit écrire à ses enfants; Si le parent n'a pas besoin d'écrire aux enfants, pourquoi vous embêtez-vous avec les tuyaux de parent à enfants? –

+0

@JonathanLeffler, code mis à jour déplacer le code parent et le code enfant dans différentes fonctions, dans ma mise en œuvre, il faudra écrire parent aux enfants, mais à ce stade, il n'a pas encore été développé en raison du problème. –

+0

L'utilisation de la variable globale 'i' pour les contrôles de boucle dans les fonctions est un désastre. Parfois, les variables globales sont nécessaires - quand elles le sont, vous devriez les utiliser. La plupart du temps, ils ne le sont pas - et quand ils ne le sont pas, vous ne devriez pas les utiliser. Les noms de variables globales à une seule lettre sont rarement appropriés. (Il est préférable de répéter la définition de «i» dans chaque fonction où cela est nécessaire que de faire comme vous l'avez fait.) Cela rend votre code très difficile à analyser. Votre boucle de lecture de chaîne conserve uniquement la dernière 'ligne' ('ligne' terminée par un caractère nul). J'imagine que c'est une façon d'engloutir tout le fichier en une seule opération. –

Répondre

1

Lorsque vous commencez à utiliser des noms comme child2_parent et parent_child2, il y a un tableau en essayant d'échapper à vos variables. Quand vous avez 4 ensembles de ces variables, c'est désastreux.

Il y avait beaucoup, beaucoup de problèmes avec le code. C'est une réécriture totale. Les erreurs sont signalées à stderr. La plupart des appels système sont vérifiés. Il y a une impression diagnostique des données lues. Il y a une fonction split_string() qui divise une chaîne en mots sur l'espace blanc. Il est utilisé dans les composants parent et enfant. Les enfants n'ont plus accès aux données de chaîne - toutes les variables globales ont disparu.

Le code est encore loin d'être optimal. Il n'y a aucun besoin particulier d'ouvrir tous les tuyaux avant de commencer les enfants; le processus est synchrone. Il serait faisable et même judicieux de créer les tuyaux pour chaque enfant à son tour. À l'heure actuelle, chaque enfant ferme seulement le quart des descripteurs de pipe qui lui sont accessibles.

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

enum { MAX_KIDS = 4 }; 
enum { LIST_SIZE = 1024 }; 
enum { MAX_WORDS = LIST_SIZE/3 }; 

static int split_string(char *data, char *words[], int max_words) 
{ 
    int num_words = 0; 
    char *src = data; 
    char *token; 
    while ((token = strtok(src, " \n\t")) != NULL) 
    { 
     words[num_words++] = token; 
     if (num_words >= max_words) 
      break; 
     src = NULL; 
    } 
    return num_words; 
} 

static void childFunction(int s, int f_pipe[2], int t_pipe[2]) 
{ 
    srand(getpid()); 
    close(f_pipe[1]); 
    close(t_pipe[0]); 
    char data[LIST_SIZE]; 
    int nbytes; 
    if ((nbytes = read(f_pipe[0], data, sizeof(data))) <= 0) 
    { 
     fprintf(stderr, "child %d (PID %d): failed to read pipe\n", s, (int)getpid()); 
     exit(1); 
    } 
    data[nbytes] = '\0'; 
    close(f_pipe[0]); 

    char *words[MAX_WORDS]; 
    int num_words = split_string(data, words, MAX_WORDS); 
    char *word = words[rand() % num_words]; 
    int len = strlen(word); 
    if (write(t_pipe[1], word, len) != len) 
    { 
     fprintf(stderr, "child %d (PID %d): failed to write [%s] to pipe\n", s, (int)getpid(), word); 
     exit(1); 
    } 
    close(t_pipe[1]); 
    exit(0); 
} 

static void parentFunction(int s, int c_pid, int t_pipe[2], int f_pipe[2], char *words[], int max_words) 
{ 
    close(t_pipe[0]); 
    close(f_pipe[1]); 

    char buffer[LIST_SIZE]; 
    char *data = buffer; 
    const char *pad = ""; 
    for (int i = s; i < max_words; i += MAX_KIDS) 
    { 
     int n = snprintf(data, (size_t)(buffer + sizeof(buffer) - data), "%s%s", pad, words[i]); 
     data += n; 
     pad = " "; 
    } 
    printf("Send [%s] to child %d\n", buffer, s); 

    /* Write list of words to child */ 
    int nbytes = data - buffer; 
    if (write(t_pipe[1], buffer, nbytes) != nbytes) 
    { 
     fprintf(stderr, "parent: failed to write to child %d (PID %d)\n", s, c_pid); 
     exit(1); 
    } 
    close(t_pipe[1]); 

    /* Read selected word from child */ 
    nbytes = read(f_pipe[0], buffer, sizeof(buffer)); 
    if (nbytes <= 0) 
    { 
     fprintf(stderr, "parent: failed to read from child %d (PID %d)\n", s, c_pid); 
     exit(1); 
    } 
    buffer[nbytes] = '\0'; 
    close(f_pipe[0]); 

    printf("parent: child %d (PID %d) played %s\n", s, c_pid, buffer); 
} 

int main(void) 
{ 
    ssize_t rread; 
    char *line = NULL; 
    size_t len = 0; 
    if ((rread = getdelim(&line, &len, '\0', stdin)) == -1) 
    { 
     fprintf(stderr, "Unexpected EOF on standard input\n"); 
     return 1; 
    } 

    printf("line [%s]\n", line); 

    char *wordlist[MAX_WORDS]; 
    int num_words = split_string(line, wordlist, MAX_WORDS); 

    printf("Word list:"); 
    int i; 
    for (i = 0; i < num_words; i++) 
    { 
     if (i % 10 == 0 && i > 0) 
      printf("%10s", ""); 
     printf(" %2d [%s]", i, wordlist[i]); 
     if (i % 10 == 9) 
      putchar('\n'); 
    } 
    if (i % 10 != 0) 
     putchar('\n'); 
    printf("%d words\n", i); 

    for (int kid = 0; kid < MAX_KIDS; kid++) 
    { 
     printf("Words for child %d:", kid); 
     for (int word = kid; word < i; word += MAX_KIDS) 
      printf(" [%s]", wordlist[word]); 
     putchar('\n'); 
    } 

    int child_parent[MAX_KIDS][2]; 
    int parent_child[MAX_KIDS][2]; 

    for (int i = 0; i < MAX_KIDS; i++) 
    { 
     if (pipe(child_parent[i]) != 0 || pipe(parent_child[i]) != 0) 
     { 
      fprintf(stderr, "failed to create pipes for child %d\n", i); 
      exit(1); 
     } 
    } 

    for (int s = 0; s < MAX_KIDS; s++) 
    { 
     int currpid = fork(); 
     if (currpid < 0) 
     { 
      fprintf(stderr, "Error when forking\n"); 
      exit(1); 
     } 
     else if (currpid == 0) 
     { 
      printf("Child : %d, pid %d:\n", s, getpid()); 
      childFunction(s, parent_child[s], child_parent[s]); 
     } 
     else 
      parentFunction(s, currpid, parent_child[s], child_parent[s], wordlist, num_words); 
    } 

    int corpse; 
    int status; 
    while ((corpse = waitpid(-1, &status, 0)) > 0) 
     printf("PID %d died with exit status 0x%.4X\n", corpse, status); 
} 

Compte tenu d'un fichier de données:

S2 SA SQ S8 S3 S6 S5 SJ S9 S7 H2 SK H9 S4 C7 
ST H6 H4 C5 HK HA HJ C8 HT H8 H7 CA H5 C6 CQ 
C4 H3 CK C9 CJ HQ D8 CT C3 C2 DQ DT DA D4 D7 
D2 D5 D6 D3 D9 

un exemple de sortie du programme est:

line [S2 SA SQ S8 S3 S6 S5 SJ S9 S7 H2 SK H9 S4 C7 
ST H6 H4 C5 HK HA HJ C8 HT H8 H7 CA H5 C6 CQ 
C4 H3 CK C9 CJ HQ D8 CT C3 C2 DQ DT DA D4 D7 
D2 D5 D6 D3 D9 
] 
Word list: 0 [S2] 1 [SA] 2 [SQ] 3 [S8] 4 [S3] 5 [S6] 6 [S5] 7 [SJ] 8 [S9] 9 [S7] 
      10 [H2] 11 [SK] 12 [H9] 13 [S4] 14 [C7] 15 [ST] 16 [H6] 17 [H4] 18 [C5] 19 [HK] 
      20 [HA] 21 [HJ] 22 [C8] 23 [HT] 24 [H8] 25 [H7] 26 [CA] 27 [H5] 28 [C6] 29 [CQ] 
      30 [C4] 31 [H3] 32 [CK] 33 [C9] 34 [CJ] 35 [HQ] 36 [D8] 37 [CT] 38 [C3] 39 [C2] 
      40 [DQ] 41 [DT] 42 [DA] 43 [D4] 44 [D7] 45 [D2] 46 [D5] 47 [D6] 48 [D3] 49 [D9] 
50 words 
Words for child 0: [S2] [S3] [S9] [H9] [H6] [HA] [H8] [C6] [CK] [D8] [DQ] [D7] [D3] 
Words for child 1: [SA] [S6] [S7] [S4] [H4] [HJ] [H7] [CQ] [C9] [CT] [DT] [D2] [D9] 
Words for child 2: [SQ] [S5] [H2] [C7] [C5] [C8] [CA] [C4] [CJ] [C3] [DA] [D5] 
Words for child 3: [S8] [SJ] [SK] [ST] [HK] [HT] [H5] [H3] [HQ] [C2] [D4] [D6] 
Send [S2 S3 S9 H9 H6 HA H8 C6 CK D8 DQ D7 D3] to child 0 
Child : 0, pid 89366: 
parent: child 0 (PID 89366) played HA 
Send [SA S6 S7 S4 H4 HJ H7 CQ C9 CT DT D2 D9] to child 1 
Child : 1, pid 89367: 
parent: child 1 (PID 89367) played S4 
Send [SQ S5 H2 C7 C5 C8 CA C4 CJ C3 DA D5] to child 2 
Child : 2, pid 89368: 
parent: child 2 (PID 89368) played C5 
Send [S8 SJ SK ST HK HT H5 H3 HQ C2 D4 D6] to child 3 
Child : 3, pid 89369: 
parent: child 3 (PID 89369) played D6 
PID 89368 died with exit status 0x0000 
PID 89367 died with exit status 0x0000 
PID 89366 died with exit status 0x0000 
PID 89369 died with exit status 0x0000 
+0

c'est exactement ce dont j'ai besoin. Je vous remercie. +1 –