270 likes | 465 Views
Como comunicar 2 procesos emparentados. Mediante una pipe sin nombre. Que queremos hacer…. Lo mismo que haría la Shell al hacer…. ps –A |grep [COMANDO] Donde [COMANDO] será un texto que buscaremos en la salida del comando ps. ¿Que hace la Shell al hacer esto?. shell. fork. fork.
E N D
Como comunicar 2 procesos emparentados Mediante una pipe sin nombre
Que queremos hacer… • Lo mismo que haría la Shell al hacer…. • ps –A |grep [COMANDO] • Donde [COMANDO] será un texto que buscaremos en la salida del comando ps.
¿Que hace la Shell al hacer esto? shell fork fork ps -A grep • El proceso que ejecutará ps escribe sus datos en la salida std (canal 1) • Hay que redireccionar la salida std del proceso que hará el ps • El proceso que ejecutará el grep, lee sus datos de la entrada std (canal 0) • Hay que redireccionar la entrada std del proceso que hará el grep
Que necesitamos • 2 procesos (emparentados, sino no se pueden usar pipes sin nombre) • 1 pipe sin nombre • Como es solo para estos procesos, no tiene sentido crear una pipe con nombre, pero también se podría usar • La pipe la usarán el proceso ps y el grep hay que crearla antes que cualquiera de los dos procesos para que la hereden
PASO 1: Esquema de procesos (simplificado) voidmain(intargc,char *argv[]) { intpid_ps,pid_grep; if (argc!=2) usage(); pid_ps=fork(); if (pid_ps==0){ // El hijo mutará a ps execlp("ps","ps","-A",(char *)NULL); error_cs("Fallo al mutar a ps"); }elseif (pid_ps<0) error_cs("Error en el primer fork (PS)"); pid_grep=fork(); if (pid_grep==0){ // El hijo mutará a grep execlp("grep","grep",argv[1],(char *)NULL); error_cs("Error al mutar a grep"); }elseif (pid_grep<0) error_cs("Error en el segundo fork(GREP)"); while(waitpid(-1,NULL,0)>0); // El padre simplemente esperará }
PASO 2: Creamos la pipe voidmain(intargc,char *argv[]) { intpid_ps,pid_grep, p[2]; if (argc!=2) usage(); pipe(p); // Creamos la pipe antes del ps y el grep pid_ps=fork(); if (pid_ps==0){ // El hijo mutará a ps execlp("ps","ps","-A",(char *)NULL); error_cs("Fallo al mutar a ps"); }elseif (pid_ps<0) error_cs("Error en el primer fork (PS)"); pid_grep=fork(); if (pid_grep==0){ // El hijo mutará a grep execlp("grep","grep",argv[1],(char *)NULL); error_cs("Error al mutar a grep"); }elseif (pid_grep<0) error_cs("Error en el segundo fork(GREP)"); while(waitpid(-1,NULL,0)>0); // El padre simplemente esperará } Necesitamos un vector de 2 enteros P[0] tendrá el canal de lectura y p[1] el de escritura
PASO 3: Redireccionar canales(ps) • El proceso ps escribirá en el canal 1 • El canal 1 debe estar vinculado a lapipe … if (pid_ps==0){ // El hijo mutará a ps dup2(p[1],1); execlp("ps","ps","-A",(char *)NULL); error_cs("Fallo al mutar a ps"); }elseif (pid_ps<0) error_cs("Error en el primer fork (PS)"); … ps 1 • Si el canal 1 estaba activo (lo normal), primero se cierra • Después se copia el contenido de la tabla de canales de la entrada p[1] en la entrada 1
PASO 4: cerrar canales(ps) • El proceso ps solo necesita elcanal 1 … if (pid_ps==0){ // El hijo mutará a ps dup2(p[1],1); close(p[0]);close(p[1]); execlp("ps","ps","-A",(char *)NULL); error_cs("Fallo al mutar a ps"); }elseif (pid_ps<0) error_cs("Error en el primer fork (PS)"); … ps 1 Antes de mutar!!!!!!
PASO 3: Redireccionar canales(grep) • El proceso grep leerá en el canal 0 • El canal 0 debe estar vinculado a lapipe … if (pid_grep==0){ // El hijo mutará a grep dup2(p[0],0); execlp(“grep",“grep",argv[1],(char *)NULL); error_cs("Fallo al mutar a grep"); }elseif (pid_grep<0) error_cs("Error en el segundo fork (GREP)"); … grep 0 • Si el canal 0 estaba activo (lo normal), primero se cierra • Después se copia el contenido de la tabla de canales de la entrada p[0] en la entrada 0
PASO 4: cerrar canales(grep) • El proceso grep solo necesitael canal 0 … if (pid_grep==0){ // El hijo mutará a grep dup2(p[0],0); close(p[0]);close(p[1]); execlp(“grep",“grep",argv[1],(char *)NULL); error_cs("Fallo al mutar a grep"); }elseif (pid_grep<0) error_cs("Error en el segundo fork (GREP)"); … grep 0 Antes de mutar!!!!!!
PASO 5: cerrar canales (padre) voidmain(intargc,char *argv[]) { intpid_ps,pid_grep, p[2]; if (argc!=2) usage(); pipe(p); // Creamos la pipe antes del ps y el grep pid_ps=fork(); if (pid_ps==0){ // El hijo mutará a ps ……. }elseif (pid_ps<0) error_cs("Error en el primer fork (PS)"); pid_grep=fork(); if (pid_grep==0){ // El hijo mutará a grep ….. }elseif (pid_grep<0) error_cs("Error en el segundo fork(GREP)"); close(p[0]);close(p[1]); while(waitpid(-1,NULL,0)>0); // El padre simplemente esperará } El padre no usa la pipe Antes del waitpid!!!!
Probad el código!!! Veremos como afecta a las estructuras de datos
¿Como afecta a las estructuras de datos? • Suponed que el programa se llama ps_grep y lo lanzamos asi: • ps_grepbash • La entrada y salida std por defecto será la consola (“tty” en la tabla) Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo T.CanalesProceso inicial Tabla Ficheros Abiertos
Estado inicial: comentarios • Tenemos tres canales ocupados: 0, 1 y 2 que corresponden con los canales de la entrada/salida/salida error std • Como la entrada/salida/salida error std. Asumimos que es la consola, podemos hacer que apunte a una única entrada de la TFO • Referencias=3 porque hay tres canales en total apuntando a ella • Como es de lectura/escritura el modo es RW • Como la consola no es un fichero de datos, no ofrece un acceso secuencial a la información, por lo tanto no ponemos un valor en la posición de l/e • Usamos la entrada 0 de la tabla de inodos • En la T. inodos deberíamos poner el número de inodo, pero en los casos que tengamos información del sistema de fichero lo simplificaremos con una etiqueta tipo “consola” o “pipe”
Ejecución concurrente • Los tres procesos estará ejecutándose a la vez, las modificaciones que pondremos aquí corresponden a una posible secuencia • Por simplicidad asumiremos que primero se ejecuta el padre, luego añadiremos las modificaciones del proceso del ps y luego las del grep. • La tabla de canales está en el PCB, pero por simplicidad pintamos solo la tabla de canales • Cada vez que hagamos un fork: • Hemos de añadir una nueva tabla de canales • Será una réplica de la de su padre • Habrá que actualizar el contador de referencias
Secuencia del padre • pipe(p); • fork(); • fork() • close(p[0]);close(p[1]); • while(waitpid(-1,null,0)>0);
1. Creamos la pipe • Hemos de añadir 1 entrada en la T.Inodos, 2 entradas en la TFO y 2 canales. Primero el acceso de lectura y luego el de escritura. Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo T.CanalesProceso inicial Tabla Ficheros Abiertos
2.3. Fork: no modifica la tabla de canales del padre Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
4. Cierra los canales : close(3);close(4) Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
Secuencia ps • dup2(p[1],1); dup2(4,1) • Cierra el canal 1 actualizar contador de referencias • Copia el canal 4 en la salida1 actualizar contador referencias • close(p[0]);close(p[1]); close(3); close(4); • Actualizar contador de referencias • execlp(“ps",“ps",”-A”,(char *)NULL); • No afecta a la tabla de canales, solo es un cambio del binario
1. Cambios proceso PS: dup2(4,1) Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
2. Cambios proceso PS: close(3);close(4); Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
Secuencia grep • dup2(p[0],0); dup2(3,0) • Cierra el canal 0 actualizar contador de referencias • Copia el canal 3 en la entrada 0 actualizar contador referencias • close(p[0]);close(p[1]); close(3); close(4); • Actualizar contador de referencias • execlp(“grep",“grep",argv[1],(char *)NULL); • No afecta a la tabla de canales, solo es un cambio del binario
1. Cambios proceso grep: dup2(3,0); Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
2. Cambios proceso grep: close(3);close(4); Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
Este es el estado cuando el proceso padre está en el waitpid y los hijos están haciendo el ps y el grep Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” Proceso “grep”
Finalización de procesos • El primero en acabar será el ps y luego el grep, ya que uno produce datos y el otro los lee. ¿ Como estarán las tablas cuando solo quede el padre justo después del waitpid? Ent.; refs.Inodo; Ent.; refs. Modo; l/e; Ent. T.Inodo Canal; entrada_tfo Proceso inicial Cuando un proceso terminase cierran todos los canalesque le queden abiertos