La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Como comunicar 2 procesos emparentados

Presentaciones similares


Presentación del tema: "Como comunicar 2 procesos emparentados"— Transcripción de la presentación:

1 Como comunicar 2 procesos emparentados
Mediante una pipe sin nombre

2 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.

3 ¿Que hace la Shell al hacer esto?
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

4 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

5 PASO 1: Esquema de procesos (simplificado)
void main(int argc,char *argv[]) { int pid_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"); }else if (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"); }else if (pid_grep<0) error_cs("Error en el segundo fork(GREP)"); while(waitpid(-1,NULL,0)>0); // El padre simplemente esperará }

6 PASO 2: Creamos la pipe Necesitamos un vector de 2 enteros
void main(int argc,char *argv[]) { int pid_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"); }else if (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"); }else if (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

7 PASO 3: Redireccionar canales(ps)
El proceso ps escribirá en el canal 1 El canal 1 debe estar vinculado a la pipe ps 1 … 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"); }else if (pid_ps<0) error_cs("Error en el primer fork (PS)"); 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

8 PASO 4: cerrar canales(ps)
El proceso ps solo necesita el canal 1 ps 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"); }else if (pid_ps<0) error_cs("Error en el primer fork (PS)"); Antes de mutar!!!!!!

9 PASO 3: Redireccionar canales(grep)
El proceso grep leerá en el canal 0 El canal 0 debe estar vinculado a la pipe grep … 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"); }else if (pid_grep<0) error_cs("Error en el segundo fork (GREP)"); 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

10 PASO 4: cerrar canales(grep)
El proceso grep solo necesita el canal 0 grep … 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"); }else if (pid_grep<0) error_cs("Error en el segundo fork (GREP)"); Antes de mutar!!!!!!

11 PASO 5: cerrar canales (padre)
void main(int argc,char *argv[]) { int pid_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 ……. }else if (pid_ps<0) error_cs("Error en el primer fork (PS)"); pid_grep=fork(); if (pid_grep==0){ // El hijo mutará a grep ….. }else if (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!!!!

12 Veremos como afecta a las estructuras de datos
Probad el código!!! Veremos como afecta a las estructuras de datos

13 ¿Como afecta a las estructuras de datos?
Suponed que el programa se llama ps_grep y lo lanzamos asi: ps_grep bash 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 3 RW - 1 2 4 5 1 “tty” 2 1 2 3 4 T.Canales Proceso inicial Tabla Ficheros Abiertos

14 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”

15 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

16 Secuencia del padre pipe(p); fork(); fork() close(p[0]);close(p[1]);
while(waitpid(-1,null,0)>0);

17 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 3 RW - 1 R 2 W 4 5 1 “tty” 2 “pipe” 1 2 3 4 T.Canales Proceso inicial Tabla Ficheros Abiertos

18 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 9 RW - 1 3 R 2 W 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 1 2 3 4

19 4. Cierra los canales : close(3);close(4)
Ent.; refs Inodo; Ent.; refs Modo; l/e; Ent. T.Inodo Canal; entrada_tfo 9 RW - 1 3 2 R 2 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 1 2 3 4

20 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

21 1. Cambios proceso PS: dup2(4,1)
Ent.; refs Inodo; Ent.; refs Modo; l/e; Ent. T.Inodo Canal; entrada_tfo 9 8 RW - 1 2 R 2 3 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 0 2 2 3 4 Proceso “grep” 1 2 3 4

22 2. Cambios proceso PS: close(3);close(4);
Ent.; refs Inodo; Ent.; refs Modo; l/e; Ent. T.Inodo Canal; entrada_tfo 8 RW - 1 2 1 R 2 3 2 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 1 2 3 4

23 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

24 1. Cambios proceso grep: dup2(3,0);
Ent.; refs Inodo; Ent.; refs Modo; l/e; Ent. T.Inodo Canal; entrada_tfo 8 7 RW - 1 1 2 R 2 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 0 1 1 2 3 4

25 2. Cambios proceso grep: close(3);close(4);
Ent.; refs Inodo; Ent.; refs Modo; l/e; Ent. T.Inodo Canal; entrada_tfo 7 RW - 1 2 1 R 2 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 1 2 3 4

26 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 7 RW - 1 R 2 W 3 4 5 1 “tty” 2 “pipe” Proceso inicial 1 2 3 4 Canal; entrada_tfo Canal; entrada_tfo Proceso “ps” 1 2 3 4 Proceso “grep” 1 2 3 4

27 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 3 RW - 1 2 4 5 1 “tty” 2 Proceso inicial 1 2 3 4 Cuando un proceso termina se cierran todos los canales que le queden abiertos


Descargar ppt "Como comunicar 2 procesos emparentados"

Presentaciones similares


Anuncios Google