2017-10-15 15 views
0

Je travaille sur une affectation où je dois créer une liste chaînée composée de processus qui communiquent via des canaux appelés nœuds. Le programme doit commencer par le processus racine et un processus enfant appelé Nœud 1. L'utilisateur dispose de quatre options, je suis bloqué sur l'option numéro 1 où l'utilisateur devrait pouvoir ajouter des nœuds (processus).Lecture d'un tube dans un processus enfant suspendu en deuxième lecture

Le processus racine doit être le seul qui demande une entrée utilisateur. Le reste devrait boucler jusqu'à ce qu'il frappe un bloc de lecture et attend d'être écrit.

Lorsque l'utilisateur entre un 1, le programme vérifie si le processus en cours est le dernier nœud (dans ce cas, le nœud 1). Si ce n'est pas le cas, le processus écrit l'entrée au nœud suivant via un canal créé avant chaque fork. Si c'est le cas, le processus réinitialise la variable isLast et crée un nouveau tube et des forks. Le processus enfant (Nœud 2) effectue ensuite une boucle et reste bloqué à la lecture, le parent suivant dans ses pas. Root demande ensuite une nouvelle fois l'utilisation.

Le problème est que le programme semble avoir aucun mal à passer par une fois et la création de nœud 2, mais la deuxième fois à travers, le nœud 1 se bloque même si la racine écrit dans « Ajouter un noeud »

Toute aide est très apprécié!

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

int main(){ 
    int isLast = 0; 
    int originPID = getpid(); 
    int input = 0; 
    int node; 
    int p[2]; 

    //Node 1 
    printf("%s\n", "Forking"); 
    pipe(p); 
    int pid = fork(); 

    //Set Node 1 to last 
    if(pid == 0){ 
     isLast = 1; 
     node = 1; 
    } 

    while(input != 4){ 
     //Node Read Block 
     if(getpid() != originPID){ 
      printf("stuck\n"); 
      read(p[0], &input, sizeof(input)); 
      printf("free\n"); 
     } 

     //MENU (Root Only) 
     if(getpid() == originPID){  
      sleep(1); 
      printf("%s", "User Options: Enter a number \n1. Add Node\n2. List Processes\n3. Remove Node\n4. Quit\n"); 
      scanf("%d", &input); 
     } 

     //(1) Add Node 
     if(input == 1){ 
      //Checks if last. 
      if(isLast == 1){ 
       isLast = 0;  //Reset isLast 

       //Create pipe and new process 
       printf("%s\n", "Forking"); 
       pipe(p); 
       pid = fork(); 
       if(pid == 0){  
        isLast = 1; 
        node++;  //Label Node 
       } 
      } 
      //Write to next node 
      else{  
       write(p[1], &input, sizeof(input));  
      } 
     } 
    } 
} 
+1

Il peut être bloqué dans une boucle éternelle en entrant par exemple 'a '; 'scanf ("% d ", & input);' alors * jamais * correspond. Vous devez vérifier la valeur de retour de 'scanf' et si aucun argument n'a été converti, jetez-le jusqu'à la fin de la ligne. –

+0

Aussi, quelle est la ligne ** 61 **, elle ne correspond pas au code de votre question. 61 dans votre question est un commentaire. Lisez également le [mcve] et faites-en un programme minimal qui présente le même problème. –

+0

@AnttiHaapala Pour la première réponse, parlez-vous du fait que si un utilisateur saisit un 'a' à l'invite, le programme entre dans une boucle éternelle? Je n'ai pas encore abordé cette partie parce que notre professeur voulait que nous ayons une contribution appropriée pour l'instant. Cependant, cela affecterait-il aussi le bloc de lecture? – DazedFury

Répondre

1

Lorsque le dernier noeud lit un 1 à partir du tuyau, il faut créer un nouveau tuyau permettant de communiquer avec le nouveau noeud est en train de créer. Je suppose que c'est pourquoi il appelle pipe(p). Mais c'est un problème, car p[0] contient sa seule copie de la poignée de fichier à partir de laquelle il lit sa propre entrée. Quand il essayera ensuite de lire l'entrée, il essaiera de lire à partir du canal qu'il a configuré pour le noeud suivant - il s'est effectivement déconnecté de son prédécesseur.

Il n'y a rien de magique dans le tableau dans lequel pipe() écrit ses poignées de fichiers. Les poignées ne sont que des entiers. Une solution simple serait donc que l'enfant crée et utilise une copie du descripteur de fichier lu qu'il hérite de son parent, au lieu de faire référence à la valeur stockée dans l'élément de tableau.

De même, vous devez être sûr qu'après la fourche, parent et enfant ferment chacun leur propre copie de la fin du tuyau qu'ils n'utiliseront pas. (Le parent ferme la fin de lecture, l'enfant ferme la fin d'écriture.) Vous pouvez peut-être faire fonctionner le programme sans, mais au minimum, cela va fuir les descripteurs de fichiers. Dans certaines circonstances, laisser des copies supplémentaires de vos descripteurs de fichier ouverts peut entraîner des blocages de programme.

+0

Merci d'avoir pris le temps d'écrire une réponse. Je suis désolé, mais pouvez-vous préciser ce que vous voulez dire en demandant à un enfant de faire une copie du descripteur de fichier, je ne comprends pas très bien.De plus, notre professeur nous a dit de ne pas fermer de tuyaux dans cette mission parce que les descripteurs de fichiers fermés seraient recyclés, ce que nous ne voulons apparemment pas. – DazedFury

+0

@DazedFury, le descripteur de fichier est la valeur stockée * dans * votre élément de tableau, pas l'élément de tableau lui-même. Vous pouvez stocker la même valeur ailleurs (c'est-à-dire une variable différente) et l'utiliser à la place. En ce qui concerne les fermetures, si votre professeur vous a dit de ne pas fermer les descripteurs de fichiers, alors, bien sûr, vous devriez faire comme ils disent. Ils ont raison de dire que les numéros de descripteurs de fichiers peuvent être réutilisés. Je ne peux pas penser à une bonne raison pour laquelle cela poserait un problème, cependant. –

+0

Ça l'a fait! Super travail, merci pour l'aide. – DazedFury