2012-01-14 11 views
5

Estoy tomando un curso de sistemas operativos y me está resultando difícil cómo se redirige la entrada con dup2 cuando tienes horquillas. Escribí este pequeño programa para tratar de darle sentido, pero no tuve éxito en pasar la producción de un nieto a un niño. Estoy tratando de imitar el comando de Unix: ps -A | wc -l. Soy nuevo en Unix, pero creo que esto debería contar las líneas de la lista de procesos en ejecución que obtengo. Entonces mi salida debería ser un solo número.¿Cómo se usan el dup2 y el tenedor juntos?

#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; 
} 

no tengo que en el código anterior, pero aquí es mi conjetura sobre cómo las cosas deben ir hacia abajo:

  • Debemos redirigir la salida estándar del comando ps -A (lo que sea generalmente impreso en la pantalla, ¿correcto?) para que el comando wc -l pueda usarlo para contar las líneas.
  • Esta salida estándar se puede redirigir utilizando dup2, como dup2 (?, 1) lo que significa redirigir la salida estándar a?. Entonces cierras?

Pregunta: ¿Dónde lo redirecciono? Sé que debería ser uno de los descriptores de archivos, pero ¿dónde debería redirigirse para que wc pueda procesarlo?

  • wc de alguna manera recibe la salida estándar.

Pregunta: ¿Cómo recibe wc la salida? A través de un parámetro execlp? ¿O el sistema operativo verifica uno de los descriptores de archivos?

  • Ejecutar wc -l.

¿Cuál de estos está cerrado y dejado abierto para que wc reciba y procese la salida de ps? Sigo pensando que esto debe pensarse al revés ya que ps necesita dar su salida a wc ... pero eso no parece tener sentido ya que tanto el niño como el nieto se están procesando en paralelo.

pipe dream

Respuesta

4

En primer lugar, vamos a fijar su código para que añadimos un poquito más de comprobación de errores a la misma, y ​​para que funcione; reemplazar el bit inferior con:

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; 
     } 
} 

Ahora, a sus preguntas:

  • Pregunta: ¿Por dónde redirección a una? Sé que debería ser uno de los descriptores de archivos, pero ¿dónde debería redirigirse para que wc pueda procesarlo?

    Los filedescriptors 0, 1, y 2 son especiales en Unix en que son la entrada estándar, salida estándar, y el error estándar. wc lee desde la entrada estándar, por lo que lo que sea dup ed a 0.

  • Pregunta: ¿Cómo recibe wc la salida? A través de un parámetro execlp? ¿O el sistema operativo verifica uno de los descriptores de archivos?

    En general, después de que un proceso haya tenido su imagen intercambiada con exec, tendrá todos los descriptores de archivo abiertos que tenía antes de exec. (Excepto por los descriptores con el indicador CLOSE_ON_EXEC establecido, pero ignórelo por ahora) Por lo tanto, si dup2 algo a 0, entonces wc lo leerá.

  • ¿Cuál de estos está cerrado y dejado abierto para que wc reciba y procese la salida de ps?

    Como se muestra arriba, puede cerrar ambos extremos de la tubería tanto en el niño como en el nieto, y todo irá bien. De hecho, la práctica estándar te recomendaría que lo hicieras. Sin embargo, la única línea realmente necesaria close en este ejemplo específico es la que yo comento como "importante" - eso es cerrar el escribir fin del tubo en el niño.

    La idea es esta: tanto el niño como el nieto tienen ambos extremos de la tubería abiertos cuando comienzan. Ahora, a través de dup, hemos conectado wc al extremo de lectura de la tubería. wc va a seguir chupando esa tubería hasta que todos los descriptores en el extremo de escritura de la tubería estén cerrados, en ese punto verá que llegó al final del archivo y se detendrá. Ahora, en el bisnieto, podemos salimos con la suya sin cerrar nada porque ps -A no va a hacer nada con ninguno de los descriptores, pero escribe en el descriptor 1, y después de ps -A termina de escupir cosas sobre algunos procesos, saldrá , cerrando todo lo que tenía. En el niño, realmente no necesitamos cerrar el descriptor de lectura almacenado en fd[0] porque wc no intentará leer nada excepto el descriptor 0. Sin embargo, tenemos que cerrar el extremo de escritura de la tubería en el niño porque de lo contrario wc se va a sentar allí con una tubería que nunca se cierra por completo.

    Como se puede ver, el razonamiento de por qué realmente no necesitamos ninguna de las líneas excepto la close uno marcado "importante" dependerá de los detalles de cómo wc y ps se van a comportar, por lo que la práctica habitual es para cerrar el extremo de un tubo que no está utilizando completamente, y mantener abierto el extremo que está utilizando solo con un descriptor. Dado que está utilizando dup2 en ambos procesos, eso significa cuatro declaraciones close como se indicó anteriormente.

EDITAR: Se actualizaron los argumentos a execlp.

+0

Daniel, gracias por la clara explicación! Una gran ayuda. Estoy obteniendo un resultado ahora, que me muestra las líneas, las palabras y el recuento de caracteres. ¿No debería el argumento "-l" solo mostrarme el recuento de líneas? Además, una pregunta relacionada: estoy accediendo a una máquina Linux a través de una terminal a través de puTTY. Cuando ejecuto ps -A | wc -l en él, obtengo el resultado 145. Supongo que eso significa que hay un total de 145 procesos que probablemente se estén ejecutando. Cuando ejecuto mi programa, obtengo 5 líneas. Cuando ejecuta ps -A a través de execlp en un programa, ¿solo muestra el padre y sus hijos? – ShrimpCrackers

+0

Nm, descubrí que execlp (...) tenía N argumentos correspondientes a arg [0], arg [1], arg [2] ... – ShrimpCrackers

+0

Ah, claro, uy. Sí, debería ser 'execlp ("/usr/bin/wc "," wc "," -l ", NULL);' y de manera similar para 'ps'. –

Cuestiones relacionadas