Question

Je suis un cours sur les systèmes d'exploitation et j'ai du mal à rediriger les entrées avec dup2 lorsque vous avez des fourches. J'ai écrit ce petit programme pour essayer d'en comprendre le sens, mais je n'ai pas réussi à transmettre la sortie d'un petit-enfant à un enfant. J'essaye d'imiter la commande unix: ps -A | wc -l. Je suis nouveau sous Unix, mais je pense que cela devrait compter les lignes de la liste des processus en cours d'exécution que j'obtiens. Ma sortie devrait donc être un seul nombre.

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

using namespace std;

int main( int argc, char *argv[] )  {

    char *searchArg = argv[ 1 ];
    pid_t pid;

    if ( ( pid = fork() ) > 0 ) {
        wait( NULL );
        cout << "Inside parent" << endl;
    } 
    else if ( pid == 0 ) {
            int fd1[ 2 ];
            pipe( fd1 );
            cout << "Inside child" << endl;

            if ( pid = fork() > 0 ) {
                dup2( fd1[ 0 ], 0 );
                close( fd1[ 0 ] );
                execlp( "/bin/wc", "-l", NULL );
            }
            else if ( pid == 0 ) {
                cout << "Inside grand child" << endl;
                execlp( "/bin/ps", "-A", NULL );
            }
        }
    return 0;
}

Je ne l'ai pas dans le code ci-dessus, mais voici mon estimation de la façon dont les choses devraient se passer:

  • Nous devons rediriger la sortie standard de la commande ps -A (tout ce qui est généralement affiché à l'écran, n'est-ce pas?) afin que la commande wc -l puisse l'utiliser pour compter les lignes.
  • Cette sortie standard peut être redirigée en utilisant dup2, comme dup2 (?, 1) ce qui signifie rediriger la sortie standard vers?. Alors vous fermez?.

Question: Où dois-je le rediriger? Je sais qu'il devrait être l'un des descripteurs de fichier, mais où doit-il être redirigé pour que wc puisse le traiter?

  • wc reçoit en quelque sorte la sortie standard.

Question: Comment wc reçoit-il la sortie? Via un paramètre execlp? Ou le système d'exploitation vérifie-t-il l'un des descripteurs de fichier?

  • Exécutez wc -l.

Lequel de ces éléments est fermé et laissé ouvert pour que wc reçoive et traite la sortie de ps? Je n'arrête pas de penser que cela doit être repensé à l'envers car ps doit donner sa sortie à wc ... mais cela ne semble pas logique puisque l'enfant et le petit-enfant sont traités en parallèle.

pipe dream

Était-ce utile?

La solution

Tout d'abord, corrigeons votre code pour y ajouter un tout petit peu plus de vérification des erreurs, et pour qu'il fonctionne; remplacez le bit du bas par:

else if ( pid == 0 ) {
        int fd1[ 2 ];
        pipe( fd1 );
        cout << "Inside child" << endl;

        if ( pid = fork() > 0 ) {
            if (dup2( fd1[ 0 ] , 0 ) < 0) {
              cerr << "Err dup2 in child" << endl;
            }
            close( fd1[ 0 ] );
            close( fd1[ 1 ] ); // important; see below
            // Note: /usr/bin, not /bin
            execlp( "/usr/bin/wc", "wc", "-l", NULL );
            cerr << "Err execing in child" << endl;
        }
        else if ( pid == 0 ) {
            cout << "Inside grand child" << endl;
            if (dup2( fd1[ 1 ] , 1 ) < 0) {
              cerr << "Err dup2 in gchild" << endl;
            }
            close( fd1[ 0 ] );
            close( fd1[ 1 ] );
            execlp( "/bin/ps", "ps", "-A", NULL );
            cerr << "Err execing in grandchild" << endl;
        }
}

Maintenant, vos questions:

  • Question: Où dois-je le rediriger? Je sais qu'il devrait être l'un des descripteurs de fichier, mais où doit-il être redirigé pour que wc puisse le traiter?

    Les descripteurs de fichier 0, 1 et 2 sont spéciaux sous Unix en ce qu'ils sont l'entrée standard, la sortie standard et l'erreur standard. wc lit à partir de l'entrée standard, donc tout ce qui est dup en 0.

  • Question: Comment wc reçoit-il la sortie? Via un paramètre execlp? Ou le système d'exploitation vérifie-t-il l'un des descripteurs de fichier?

    En général, après qu'un processus a eu son image échangée avec exec, il aura tous les descripteurs de fichier ouverts qu'il avait avant exec. (Sauf pour les descripteurs avec l'indicateur CLOSE_ON_EXEC défini, mais ignorez cela pour le moment) Par conséquent, si vous générez un code générique pour dup2, alors 0 le lira.

  • Lequel de ces éléments est fermé et laissé ouvert pour que wc reçoive et traite la sortie de ps?

    Comme indiqué ci-dessus, vous pouvez fermer les deux extrémités du tuyau chez l'enfant et le petit-enfant, et ce sera très bien. En fait, la pratique courante vous recommande de le faire. Cependant, la seule ligne wc vraiment nécessaire dans cet exemple spécifique est celle que je commente comme "importante" - qui ferme l'extrémité write du tube dans le fils.

    L'idée est la suivante: l'enfant et le petit-enfant ont les deux extrémités du tuyau ouvertes lorsqu'ils démarrent. Maintenant, via close, nous avons connecté dup à l'extrémité de lecture du tube. wc va continuer à sucer ce tube jusqu'à ce que tous les descripteurs à l'extrémité d'écriture du tube soient fermés, à quel point il verra qu'il est arrivé à la fin du fichier et s'arrêtera. Maintenant, chez le petit-enfant, nous pouvons nous en sortir sans rien fermer car wc ne va rien faire avec aucun des descripteurs mais écrire dans le descripteur ps -A, et après que 1 ait fini de cracher des informations sur certains processus, il se terminera , fermant tout ce qu'il avait. Dans l'enfant, nous n'avons pas vraiment besoin de fermer le descripteur de lecture stocké dans ps -A car fd[0] n'essaiera pas de lire à partir d'autre chose que du descripteur wc. Cependant, nous devons fermer la fin d'écriture du tube dans le fils, sinon 0 va simplement rester là avec un tube qui n'est jamais complètement fermé.

    Comme vous pouvez le voir, la raison pour laquelle nous n'avons pas vraiment besoin de l'une des lignes wc à l'exception de celle marquée "important" dépend des détails du comportement de close et wc, donc la pratique standard est de fermez l'extrémité d'un tuyau que vous n'utilisez pas complètement et gardez ouverte l'extrémité que vous utilisez avec un seul descripteur. Puisque vous utilisez ps dans les deux processus, cela signifie quatre instructions dup2 comme ci-dessus.

EDIT: mise à jour des arguments pour close.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top