Documentos de Académico
Documentos de Profesional
Documentos de Cultura
El estndar POSIX
POSIX: Interfaz de sistemas operativos portables. Basado en UNIX
A pesar de que UNIX es ya de por s estndar, haba muchos sabores que impositiblitaban la transportabilidad de los programas (cdigo fuente) Disponible en UNIX / LINUX En forma de subsistema en Windows NT / XP El estndar define: Tipos de datos Nombres de funciones Valores devueltos por las funciones Es habitual que los recursos se referencien mediante un nmero entero >= 0 que recibe el nombre de descriptor.
Fork () - 1
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
Padre
Fork () - 2
Proceso Padre Proceso Hijo
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
Padre
Hijo
Suponemos que se pudo crear el proceso hijo (fork devuelve nmeros no negativos) Ambos procesos continan ejecutando la siguiente sentencia al fork().
Fork () - 3
Proceso Padre Proceso Hijo
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
Padre
Hijo
Fork () - 4
Proceso Padre Proceso Hijo
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
# include <stdio.h> main() { int pid; /************************************************ creacin de un proceso concurrente con el creador *************************************************/ pid=forck (); if ((pid == -1) { printf ("error en creacion de proceso hijo\n"); exit(1); } else if ( pid == 0) /* proceso hijo */ { printf ("Proceso hijo 1\n"); fflush(stdout); exit (0); /* terminacion con codigo 0 */ } else /* proceso padre */ { printf ("Proceso padre\n"); fflush(stdout); wait (0); } }
Padre
Hijo El padre ve que fork() devuelve el PID del hijo, y sigue una rama del if. Espera bloqueado (wait) a que el hijo termine. El hijo ve que fork() devuelve un 0 y sigue la otra rama del if.
Funciones relacionadas:
Para saber su propio PID: getpid(); Para saber el PID del padre: getppid(); Para no tener problemas, debemos incluir los prototipos que estn en #include <sys/types.h> #include <unistd.h>
wait ()
Cuando en UNIX un proceso termina, hace que terminen todos sus hijos (finalizacin en cascada).
Para hacer que el hijo sobreviva a la muerte del padre (ej uso de nohup en el shell) el proceso hijo, ya no es hijo de su padre, sino que es adoptado por el proceso init que siempre est vivo.
Para hacer que el padre espere a que el hijo termine (y no muera antes que su hijo, haciendo que el hijo tambin muera), se debe usar la funcin wait ().
Esta funcin devuelve el pid del hijo terminado. Si tiene varios hijos el mismo padre, wait() desbloquea al padre cuando CUALQUIER hijo termina. Si tenemos que esperar a que finalicen todos, habr un wait() por cada hijo. Con la funcin waitpid() se puede esperar a la finalizacin de un hijo en particular (el padre conoce explcitamente los pids de sus hijos)
IMPORTANTE: el uso de fflush () penaliza la concurrencia, y slo debe utilizarse cuando sea estrictamente necesario, cono en el caso de una traza para depuracin.
Depuracin de programas 2
printf (msj1); F(....); printf (msj2);
Buffer de salida El uso de buffers de E/S aumenta la eficiencia del sistema, permitiendo un mayor grado de concurrencia. Es decir, el proceso puede seguir ejecutando incluso antes de que la operacin de salida se haya completado.
Depuracin de programas 3
printf (msj1); F(....); printf (msj2);
msj1 El buffer de salida no se descarga inmediatamente en el dispositivo (p.ej. pantalla). La escritura se hace Cuando est lleno Cuando se le indica que as lo haga A intervalos regulares de tiempo. Cuando el S.O. considera oportuno, p.ej. cuando no tiene otra tarea ms importante que hacer
Depuracin de programas 4
printf (msj1); F(....); printf (msj2);
msj1 Error grave Posiblemente genera un fichero Core
El proceso termina y el S.O. elimina todas las tareas que este proceso tena pendientes, entre ellas las de vaciar sus buffers de salida. El mensaje msj1 no llega a imprimirse.
Depuracin de programas 5
printf(msj1); fflush(NULL); F(....); printf(msj2); fflush (NULL);
Buffer de salida
Depuracin de programas 6
printf(msj1); fflush(NULL); F(....); printf(msj2); fflush (NULL);
msj1 printf: el mensaje va al buffer fflush: el proceso pide al S.O. que vace el buffer, y no continua su ejecucin hasta que el S.O. haya enviado el contenido del buffer al dispositivo. Est penalizando la concurrencia.
Depuracin de programas 7
Pantalla msj1
Al producirse el error, el proceso termina, pero ya sabemos que el error se produjo al entrar en la funcin F, puesto que ha aparecido msj1 pero no msj2.
Error grave
Hilos POSIX - 1
Permiten la ejecucin concurrente de varias secuencias de instrucciones asociadas a diferentes funciones dentro de un mismo proceso Los hilos hermanos entre s comparten la misma imagen de memoria, es decir:
Cdigo, variables de memoria globales, y los dispositivos y ficheros que tuviera abierto el padre.
Cdigo Variables Globales PC: localiza la siguiente Instruccin a ejecutar en la funcin principal Reg. CPU Pila: Variables locales de la funcin F
Hilos POSIX - 2
Permiten la ejecucin concurrente de varias secuencias de instrucciones asociadas a diferentes funciones dentro de un mismo proceso Los hilos hermanos entre s comparten la misma imagen de memoria, es decir:
Cdigo, variables de memoria globales, y los dispositivos y ficheros que tuviera abierto el padre.
Proceso padre
PC: localiza la siguiente Instruccin a ejecutar en la funcin F Reg. CPU Pila: Parms. de llamada a la funcin F Variables locales de la funcin F
PC: localiza la siguiente Instruccin a ejecutar en la funcin G Reg. CPU Pila: Parms. de llamada a la funcin G Variables locales de la funcin G
Hilos - 3
Consumen menos memoria. Cuesta menos crearlos. Ya tienen disponible un mecanismo de comunicacin entre ellos: las variables globales que son compartidas.
Si bien el uso de variables globales est totalmente desaconsejado en otras circunstancias, en concurrencia a travs de hilos es el mtodo idneo para compartir informacin. Cuando alguien se atreve a programar de manera concurrente con hilos, se da por supuesto que sabe programar de forma correcta, y podr afrontar sin problemas las posibles tareas de depuracin.
Es ms sencillo hacer un cambio de contexto entre hilos, lo que los hace ideales para la realizacin de tareas concurrentes cooperativas. La creacin de hilos no es una tarea estndar de UNIX
Hay que incluir una biblioteca de funciones especfica en la lnea de compilacin: gcc fuente.c -lpthread
Principal pthread_create()
pthread_create(&id, NULL, funcin, args): crea un hilo que se asocia a la ejecucin de la funcin que se indica en forma de puntero a funcin, siempre de tipo void; tambin se adjunta la lista de argumentos, pthread_exit(): final de la ejecucin de un hilo. Ser la ltima sentencia ejecutada por el hilo. pthread_kill():detiene la ejecucin del hilo especificado pthread_join(): espera la finalizacin del hilo especificado. pthread_self(): permite que un hilo se identifique a s mismo
Hilo 1 (Principal)
Hilo 2 (funcin F)
Ejercicio 1
Un programa que cree N procesos hijos, tal que todos sean "hermanos' entre s, es decir, que todos sean hijos directos del programa principal main (). Un programa que cree N procesos hijos, tal que el proceso main () slo puede tener un hijo, que a su vez slo puede tener otro nico proceso hijo, y as sucesivamente.
P
P H1 H2 H3
Ejercicio 2
escribe(n) el valor de n puede ser 0, 1, 2, 3. La funcin escribir en orden creciente nmeros menores que 1000, uno en cada lnea y con tres cifras. Los nmeros estarn encolumnados a partir de la columna 3n. El primer nmero ser el n, y entre un nmero y el siguiente hay una diferencia de 4. Escribir un programa C que lance 4 procesos concurrentes que correspondan respectivamente a la ejecucin de las funciones escribe(0), escribe(1), escribe(2) y escribe(3).
Con procesos pesados Con hilos.
escribe(0) 000 004 008 ... escribe(1) 001 005 009 ...