Programación Concurrente y Tiempo Real Tema 1. Conceptos Básicos Escuela Superior de Informática Universidad de Castilla-La Mancha Curso 2011/2012 Grado en Ing. Informática Proceso | Prog. Concurrente | Prog. TR Tema 1. Conceptos Básicos El concepto de proceso 1. El concepto de proceso 1.1. Gestión básica de procesos [Silber 3.1] 1.2. Primitivas POSIX [Robb 2.5-2.7] [Rochk 5.1-5.7] 1.3. Procesos e hilos [Silber 4.1, 4.3.1] 2. Fundamentos de prog. concurrente pila instr_1 instr_2 instr_3 … instr_i 3. Fundamentos de prog. en TR … memoria carga del ejecutable en memoria datos instr_n texto programa Curso 2011/2012 Grado en Ing. Informática Curso 2011/2012 Proceso | Prog. Concurrente | Prog. TR Estados de un proceso proceso Trp 3 de 41 Proceso | Prog. Concurrente | Prog. TR Identificadores ID proceso admitido nuevo terminado interrupción pid_t getpid (void); // ID del proceso pid_t getppid (void); // ID del proceso padre salida preparado #include <sys/types.h> #include <unistd.h> en ejecución ID usuario terminación E/S en espera #include <sys/types.h> #include <unistd.h> espera E/S uid_t getuid (void); // ID del usuario uid_t geteuid (void); // ID del usuario efectivo Curso 2011/2012 Trp 4 de 41 Curso 2011/2012 Trp 5 de 41 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() fork() proceso_A #include <sys/types.h> #include <unistd.h> fork() pid_t fork (void); // 0 al hijo; ID del hijo al padre proceso_A (cont.) proceso_B (hijo) Ejemplo fork int *valor = malloc(sizeof(int)); *valor = 0; fork(); *valor = 13; printf("%ld: %d\n", (long)getpid(), *valor); // ¿? hereda_de Curso 2011/2012 Trp 6 de 41 Curso 2011/2012 Trp 7 de 41 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() + exec() proceso_A Cadena de procesos #include <sys/types.h> #include <unistd.h> #include <stdio.h> 1 int main (void) { int i = 1, n = 4; pid_t childpid; 2 fork() proceso_A (cont.) proceso_B (hijo) 3 for (i = 1; i < n; i++) // ? execl() SIGCHLD return 0; 4 } Curso 2011/2012 wait() Trp 8 de 41 Curso 2011/2012 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() + exec() exit() zombie Limpieza tabla proc Trp 9 de 41 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() + exec() Ejemplo. Padre crea n hijos Primitivas básicas #include <unistd.h> Padre int execl (const char *path, const char *arg, ...); int execlp (const char *file, const char *arg, ...); int execle (const char *path, const char *arg, ..., char *const envp[]); // padre.c int execv (const char *path, char *const argv[]); int execvp (const char *file, char *const argv[]); int execve (const char *path, char *const argv[], char *const envp[]); for (i = 1; i <= n; i++) switch(childpid = fork()) { case 0: // Código del hijo. execl("./exec/hijo", "hijo", argv[1], NULL); break; // Para evitar entrar en el for. } // ¡Faltaría la espera del padre a los hijos! Curso 2011/2012 Trp 10 de 41 pid_t childpid; int n = atoi(argv[1]), i; Curso 2011/2012 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: fork() + exec() Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: wait() Hijo Primitivas básicas // hijo.c #include <sys/types.h> #include <sys/wait.h> int main (int argc, char *argv[]) { hijo(argv[1]); return 0; } pid_t wait (int *status); pid_t waitpid (pid_t pid, int *status, int options); // BSD style pid_t wait3 (int *status, int options, struct rusage *rusage); pid_t wait4 (pid_t pid, int *status, int options, struct rusage *rusage); void hijo (const char *num_hermanos) { printf("¡Soy %ld y tengo %d hermanos!\n", (long)getpid(), atoi(num_hermanos) - 1); } Curso 2011/2012 Trp 11 de 41 Trp 12 de 41 Curso 2011/2012 Trp 13 de 41 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: signal() Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: wait() Primitivas básicas Padre #include <sys/types.h> #include <signal.h> #include <unistd.h> // Se espera la terminación de los procesos... if (signal(SIGCHLD, esperar) == SIG_ERR) { fprintf(stderr, "No se esperó a un proceso.\n"); exit(1); } typedef void (*sighandler_t)(int); sighandler_t signal (int signum, sighandler_t handler); // Manejo de Ctrol+C. if (signal(SIGINT, controlador) == SIG_ERR) { fprintf(stderr, "Terminación incorrecta.\n"); exit(1); } int kill (pid_t pid, int sig); int pause (void); while(1) // Bucle infinito de espera. pause(); // A la espera de señales. Curso 2011/2012 Trp 14 de 41 Curso 2011/2012 Trp 15 de 41 Proceso | Prog. Concurrente | Prog. TR Creación de procesos :: wait() Proceso | Prog. Concurrente | Prog. TR Procesos e hilos Padre void esperar (int senhal) { int i; while (wait3(&i, WNOHANG, NULL) > 0); } código datos registros archivos código pila registros pila void controlador (int senhal) { printf("\nCtrl+c capturada.\n"); printf("Finalizando...\n\n"); // Liberar recursos... printf("OK!\n"); // Salida del programa. exit(0); datos registros pila archivos registros pila hebra } Curso 2011/2012 Trp 16 de 41 Curso 2011/2012 Proceso | Prog. Concurrente | Prog. TR Pthreads Proceso | Prog. Concurrente | Prog. TR Pthreads Especificación POSIX, no implementación Pthread int main (int argc, char *argv[]) { pthread_t tid; pthread_attr_t attr; Pthread #include <pthread.h> if (argc != 2) { fprintf(stderr, "Uso: ./pthread <entero>\n"); return -1; } int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); int pthread_join Trp 17 de 41 pthread_attr_init(&attr); // Att predeterminados. // Crear el nuevo hilo. pthread_create(&tid, &attr, mi_hilo, argv[1]); pthread_join(tid, NULL); // Esperar finalización. (pthread_t thread, void **retval); printf("Suma total: %d.\n", suma); return 0; } Curso 2011/2012 Trp 18 de 41 Curso 2011/2012 Trp 19 de 41 Proceso | Prog. Concurrente | Prog. TR Pthreads Tema 1. Conceptos Básicos Pthread 1. El concepto de proceso void *mi_hilo (void *valor) { int i, ls; ls = atoi(valor); i = 0, suma = 0; 2. Fundamentos de prog. concurrente 2.1. 2.2. 2.3. 2.4. while (i <= ls) suma += (i++); pthread_exit(0); } Problema del productor/consumidor [Silber 6.1] La sección crítica [Silber 6.2-6.4] Mecanismos básicos de sincron. [Silber 6.5, 6.7] Interbloqueos y tratamiento del deadlock [Silber 7] 3. Fundamentos de prog. en TR Compilación $ gcc -lpthread pthread.c -o pthread $ ./pthread 7 Curso 2011/2012 Trp 20 de 41 Curso 2011/2012 Grado en Ing. Informática Proceso | Prog. Concurrente | Prog. TR Buffer limitado Proceso | Prog. Concurrente | Prog. TR Productor/consumidor cont++ while (1) { // Produce en nextP. r1 = cont while (cont == N); r1 = r1 + 1 // No hacer nada. buffer[in] = nextP; cont = r1 in = (in + 1) % N; cont++; } while (1) { while (cont == 0); // No hacer nada. nextC = buffer[out]; out = (out + 1) % N; cont--; // Consume nextC. } while (1) { // Produce en nextP. while ((in + 1) % N == out); // No hacer nada. buffer[in] = nextP; in = (in + 1) % N; } while (1) { while (in == out); // No hacer nada. nextC = buffer[out]; out = (out + 1) % N; // Consume nextC. } Curso 2011/2012 Trp 22 de 41 do { SECCIÓN_ENTRADA r2 = cont r2 = r2 - 1 cont = r2 p: p: c: c: p: c: Curso 2011/2012 r1 = r1 = r2 = r2 = cont cont cont r1 + 1 cont r2 - 1 = r1 = r2 Trp 23 de 41 Proceso | Prog. Concurrente | Prog. TR Sección crítica cont-- Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Sol 1 (2 proc) 1. Exclusión mutua 2. Progreso 3. Espera limitada do { while (turn != i); SECCIÓN_CRÍTICA 1. Exclusión mutua 2. Progreso 3. Espera limitada SECCIÓN_CRÍTICA SECCIÓN_SALIDA turn = j; SECCIÓN_RESTANTE SECCIÓN_RESTANTE while(1); while(1); Curso 2011/2012 Trp 24 de 41 Curso 2011/2012 Trp 25 de 41 Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Sol 2 (2 proc) do { flag[i] = true; while (flag[j]); Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Peterson (2 proc) 1. Exclusión mutua 2. Progreso 3. Espera limitada do { flag[i] = true; turn = j; while (flag[j] && turn == j); SECCIÓN_CRÍTICA SECCIÓN_CRÍTICA flag[i] = false; flag[i] = false; SECCIÓN_RESTANTE SECCIÓN_RESTANTE 1. Exclusión mutua 2. Progreso 3. Espera limitada while(1); while(1); Curso 2011/2012 Trp 26 de 41 Curso 2011/2012 Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Lamport (n proc) Trp 27 de 41 Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Hardware do { do { eleccion[i] = true; num[i] = max(num[0], ..., num[n]) + 1; elección[i] = false; for (j = 0; j < n; j++) while (elección[j]); while (num[j] != 0 && (num[j], j) < (num[i], i)); adquirir_cerrojo SECCIÓN_CRÍTICA Operaciones atómicas liberar_cerrojo SECCIÓN_CRÍTICA num[i] = 0; while(1); Curso 2011/2012 SEC_REST 1. Exclusión mutua 2. Progreso 3. Espera limitada Trp 28 de 41 SECCIÓN_RESTANTE while(1); Curso 2011/2012 Trp 29 de 41 Proceso | Prog. Concurrente | Prog. TR Sección crítica :: Swap Proceso | Prog. Concurrente | Prog. TR Sincronización :: Semáforos do { do { key = true; while (key == true) swap(&lock, &key); wait (sem) SECCIÓN_CRÍTICA void swap (boolean *a, boolean *b) { // a := b // b := a } lock = false; SECCIÓN_RESTANTE Operaciones atómicas SECCIÓN_CRÍTICA swap while(1); signal (sem) SECCIÓN_RESTANTE while(1); Curso 2011/2012 Trp 30 de 41 Curso 2011/2012 Trp 31 de 41 Proceso | Prog. Concurrente | Prog. TR Sincronización :: Semáforos Proceso | Prog. Concurrente | Prog. TR Sincronización :: Paso de mensajes Memoria compartida while (1) { // Produce en nextP. wait (empty); wait (mutex); // Guarda nextP en buffer. signal (mutex); signal (full); } while (1) { wait (full); wait (mutex); // Rellenar nextC. signal (mutex); signal (empty); // Consume nextC. } Message Message Message Proceso1 Proceso2 Message Message Message Curso 2011/2012 Trp 32 de 41 Curso 2011/2012 Trp 33 de 41 Proceso | Prog. Concurrente | Prog. TR Sincronización :: Paso de mensajes Proceso 1 Proceso 2 while (1) { // W_previo_1 send ('*', P2) // W_restante_1 } while (1) { // W_previo_2 receive (&msg, P1) // W_restante_2 } Proceso | Prog. Concurrente | Prog. TR Sincronización :: Monitores Datos compartidos Condiciones x y Operaciones Código inicialización Sincronización (P2 no avanza hasta que no recibe de P1) Operaciones con exclusión mutua dentro del monitor Curso 2011/2012 Trp 34 de 41 Curso 2011/2012 Trp 35 de 41 Proceso | Prog. Concurrente | Prog. TR Interbloqueos Proceso | Prog. Concurrente | Prog. TR Grafos de asignación de recursos R1 R1 Condiciones de Coffman ● ● ● ● Exclusión mutua Retener y esperar No apropiación Espera circular R2 P1 Esperando R2... P={P1, P2, P3} R={R1, R2, R3, R4} E={P1-->R1, R1-->P2, ...} P1 P2 P3 P2 Esperando R1... R2 Curso 2011/2012 R3 Trp 36 de 41 Curso 2011/2012 R4 Trp 37 de 41 Proceso | Prog. Concurrente | Prog. TR Grafos de asignación de recursos R1 Proceso | Prog. Concurrente | Prog. TR Tratamiento del deadlock Métodos tratamiento deadlock R3 P2 R1 P1 P2 P3 P1 Impedir o evitar Detectar y recuperar P3 Ignorar 1 Prevención Evasión Evitar las 4 condiciones Coffman Política asignación recursos Info sobre el estado de recursos 2 Algoritmo detección P4 R2 R4 R2 Curso 2011/2012 Trp 38 de 41 3 Algoritmo recuperación Curso 2011/2012 Trp 39 de 41 Proceso | Prog. Concurrente | Prog. TR Evasión del deadlock Tema 1. Conceptos Básicos 1. El concepto de proceso Algoritmo del banquero 2. Fundamentos de prog. concurrente Peticiones de recursos 3. Fundamentos de prog. en TR Algoritmo de seguridad ¿Estado seguro? No Deshacer 3.1. Definición de STR [Burns 1] 3.2. Características [Burns 1] 3.3. Introducción al diseño de STR [Burns 2] Sí Asignar recursos Curso 2011/2012 Trp 40 de 41 Curso 2011/2012 Grado en Ing. Informática