Programación Concurrente y Tiempo Real Tema 2. Semáforos y Memoria Compartida Escuela Superior de Informática Universidad de Castilla-La Mancha Curso 2011/2012 Grado en Ing. Informática Conceptos | Implementación | Problemas | Patrones Tema 2. Semáforos y Memoria Compartida Semáforos. ¿Qué, cómo y por qué? 1. Conceptos básicos [Silber 6.5] p1: proceso p1: proceso 1 2. Implementación [Rochk 7.10, 7.14] [Robb 8.3] 3. Problemas clásicos de sincronización wait [p1 bloqueado] sem (1) [Downey 4, 5] sem (0) 2 wa it [decremento] 4. Patrones de sincronización básicos p1: proceso [p1 desbloqueado] sem (-1) sem (0) 4 signa l [incremento] p2: proceso [Downey 3] 5 3 cr eación [inicialización] p2: proceso * Downey, A.B., The Little Book of Semaphores Curso 2011/2012 Grado en Ing. Informática Curso 2011/2012 Conceptos | Implementación | Problemas | Patrones Ejemplo de sincronización P2 P3 P1 P2 P3 r1 s1 t1 r1 s1 t1 r2 S(a) t2 W(a) s2 S(c) r3 W(c) t3 S(b) s3 S(d) r4 W(b) t4 r5 W(d) t5 r2 r3 s2 b s3 c d t2 t3 r4 s4 t4 r5 s5 t5 Conceptos | Implementación | Problemas | Patrones Semáforos nombrados en POSIX P1 a Trp 3 de 24 s4 Manipulación de semáforos #include <semaphore.h> // Devuelve un puntero al semáforo o SEM FAILED. sem_t *sem_open( const char *name, // Nombre del semáforo. int oflag, // Flags. mode_t mode, // Permisos. unsigned int value // Valor inicial. ); int sem_close (sem_t *sem); int sem_unlink (const char *name); int sem_wait (sem_t *sem); int sem_post (sem_t *sem); s5 Curso 2011/2012 Trp 4 de 24 Curso 2011/2012 Trp 5 de 24 Conceptos | Implementación | Problemas | Patrones Semáforos nombrados en POSIX Conceptos | Implementación | Problemas | Patrones Semáforos nombrados en POSIX TAD semáforo crear_sem #ifndef __SEMAFOROI_H__ #define __SEMAFOROI_H__ #include <semaforoI.h> sem_t *crear_sem (const char *name, unsigned int valor) { sem_t *sem; #include <semaphore.h> // Crea un semáforo POSIX. sem_t *crear_sem (const char *name, unsigned int valor); // Obtener un semáforo POSIX (ya existente). sem_t *get_sem (const char *name); // Cierra un semáforo POSIX. void destruir_sem (const char *name); // Incrementa el semáforo. void signal_sem (sem_t *sem); // Decrementa el semáforo. void wait_sem (sem_t *sem); sem = sem_open(name, O_CREAT, 0644, valor); if (sem == SEM_FAILED) { fprintf(stderr, "Error al crear el semáforo: %s\n", strerror(errno)); exit(1); } return sem; } #endif Curso 2011/2012 Trp 6 de 24 Curso 2011/2012 Trp 7 de 24 Conceptos | Implementación | Problemas | Patrones Memoria compartida en POSIX Conceptos | Implementación | Problemas | Patrones Memoria compartida en POSIX Gestión de segmentos de memoria Mapping #include <mman.h> #include <unistd.h> #include <sys/mman.h> void *mmap( void *addr, size_t length, int prot, int flags, int fd, off_t offset ); // Devuelve el descriptor de archivo o -1 si error. int shm_open( const char *name, // Nombre del segmento. int oflag, // Flags. mode_t mode // Permisos. ); int shm_unlink (const char *name); int close (int fd); int ftruncate (int fd, off_t length); // // // // // // Dirección de memoria. Longitud del segmento. Protección. Flags. Descriptor de archivo. Desplazamiento. int munmap( void *addr, // Dirección de memoria. size_t length // Longitud del segmento. ); Curso 2011/2012 Trp 8 de 24 Curso 2011/2012 Trp 9 de 24 Conceptos | Implementación | Problemas | Patrones Variable entera compartida Conceptos | Implementación | Problemas | Patrones Variable entera compartida TAD Variable crear_var #ifndef __VARIABLEI_H__ #define __VARIABLEI_H__ int crear_var (const char *name, int valor) { int shm_fd; int *p; // Crea un objeto de memoria compartida. // Devuelve el descriptor de archivo. int crear_var (const char *name, int valor); // Obtiene el descriptor asociado a la variable. int obtener_var (const char *name); // Destruye el objeto de memoria compartida. void destruir_var (const char *name); // Modifica el valor del objeto de memoria compartida. void modificar_var (int shm_fd, int valor); // Consulta el valor del objeto de memoria compartida. void consultar_var (int shm_fd, int *valor); #endif Curso 2011/2012 Trp 10 de 24 2 // Establecer el tamaño. if (ftruncate(shm_fd, sizeof(int)) == -1) { fprintf(stderr, "...", strerror(errno)); exit(1); } Curso 2011/2012 Trp 11 de 24 Conceptos | Implementación | Problemas | Patrones Variable entera compartida 1 // Abre el objeto de memoria compartida. shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { fprintf(stderr, "Error al crear la variable: %s\n", strerror(errno)); exit(1); } Conceptos | Implementación | Problemas | Patrones El buffer limitado crear_var int crear_var (const char *name, int valor) { int shm_fd; int *p; 3 // ... // Mapeo del objeto de memoria compartida. p = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (p == MAP_FAILED) { fprintf(stderr, "...", strerror(errno)); exit(1); } *p = valor; munmap(p, sizeof(int)); // Unmapping. return shm_fd; 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. 4 } } Curso 2011/2012 Trp 12 de 24 Curso 2011/2012 Trp 13 de 24 Conceptos | Implementación | Problemas | Patrones Lectores y escritores Conceptos | Implementación | Problemas | Patrones El puente de un solo carril Proceso lector Proceso escritor wait(mutex); num_lectores++; if num_lectores == 1 then wait(acceso_esc); signal(mutex); // SC: Lectura // ... wait(mutex); num_lectores--; if num_lectores == 0 then signal(acceso_esc); signal(mutex); wait(acceso_esc); // SC: Escritura // ... signal(acceso_esc); Norte Sur Curso 2011/2012 Trp 14 de 24 Curso 2011/2012 Trp 15 de 24 Conceptos | Implementación | Problemas | Patrones Filósofos comensales Conceptos | Implementación | Problemas | Patrones Filósofos comensales (sin deadlock) Proceso filósofo i #define N 5 #define IZQ (i-1) % 5 #define DER (i+1) % 5 Proceso filósofo while (1) { // Pensar... wait(palillos[i]); wait(palillos[(i+1) % 5]); // Comer... signal(palillos[i]); signal(palillos[(i+1) % 5]); } void coger_palillos (int i) { wait(mutex); estado[i] = HAMBRIENTO; prueba(i); signal(mutex); wait(sem[i]); } int estado[N]; sem_t mutex; sem_t sem[N]; void filosofo (int i) { while (1) { pensar(); coger_palillos(i); comer(); dejar_palillos(i); } } Curso 2011/2012 Trp 16 de 24 void dejar_palillos (int i) { wait(mutex); estado[i] = PENSANDO; prueba(i - 1); prueba(i + 1); signal(mutex) } Curso 2011/2012 Trp 17 de 24 Conceptos | Implementación | Problemas | Patrones El barbero dormilón Consejos útiles Proceso cliente Proceso barbero 1. si 1.1 2. si 2.1 2.2 2.3 2.4 2.5 2.6 2.7 1. 2. 3. 4. 5. no sillas libres, marcharse hay sillas libres, sentarse esperar sillón levantarse silla ocupar sillón despertar barbero esperar fin levantarse sillón Conceptos | Implementación | Problemas | Patrones dormir despertar cortar notificar fin volver a 1 1 Identificación de procesos 2 3 Identificación de clases Identificación de recursos compartidos 4 Identificación de eventos de sincronización Curso 2011/2012 Trp 18 de 24 Curso 2011/2012 Conceptos | Implementación | Problemas | Patrones El problema de los caníbales ? 5 Implementación Trp 19 de 24 Conceptos | Implementación | Problemas | Patrones La Navidad y Santa Claus ? ? ? ? Curso 2011/2012 Trp 20 de 24 Curso 2011/2012 Trp 21 de 24 Conceptos | Implementación | Problemas | Patrones Reutilizando conocimiento... Reutilizando conocimiento... Señalización (signaling) Mutex Proceso A Proceso B sentencia a1 signal(sem); wait(sem); sentencia b1; Rendezvous Proceso A Proceso B wait(mutex); // Sección crítica cont = cont + 1; signal(mutex); wait(mutex); // Sección crítica cont = cont + 1; signal(mutex); Multiplex Proceso A Proceso B sentencia a1 sentencia a2 sentencia b1; sentencia b2; Curso 2011/2012 Trp 22 de 24 Conceptos | Implementación | Problemas | Patrones Reutilizando conocimiento... Exclusión mutua categórica Marcador (scoreboard) Interruptor (lightswicht) Barrera (barrier) Cola FIFO (FIFO queue) Curso 2011/2012 Conceptos | Implementación | Problemas | Patrones Trp 24 de 24 wait(multiplex); // Sección crítica signal(multiplex); Curso 2011/2012 Trp 23 de 24