Descargar la presentación
La descarga está en progreso. Por favor, espere
1
Tema 7: Concurrencia y Sincronización
Sistemas Operativos Tema 7: Concurrencia y Sincronización
2
Tema 7: Concurrencia y Sincronización
Índice: Suspensión y Reanudación Semáforos Propiedades y Características de los Semáforos Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización 2
3
Tema 7: Concurrencia y Sincronización
Índice: Suspensión y Reanudación Semáforos Propiedades y Características de los Semáforos Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización 3
4
Tema 7: Concurrencia y Sincronización
1. Suspensión y Reanudación Tema 7: Concurrencia y Sincronización Primitivas más simples: sleep () Bloquea al proceso que la invoca wakeup (int pid) Reanuda a proceso cuyo PID se indica ¿Y si dicho proceso no está sleeping? La llamada a wakeup() no tiene efecto Se recuerda la llamada para que el próximo sleep() que haga el proceso no tenga efecto. Se trata como un error.
5
Tema 7: Concurrencia y Sincronización
1. Suspensión y Reanudación Tema 7: Concurrencia y Sincronización Implementación: ¡trivial! sleep () Nuevo estado proceso llamante: bloqueado Insertar en lista de procesos bloqueados Activar bit “sleeping” en PCB para indicar causa de bloqueo wakeup (int pid) Nuevo estado proceso despertado: preparado Quitar de lista de procesos bloqueados e insertar en preparados Desactivar bit “sleeping” en PCB Aclarar que la implementación de wakeup() depende de cómo se trata el caso en que el proceso despertado no estuviese durmiendo. La que aquí se cita es para el caso de que se wakeup() no tenga efecto.
6
Tema 7: Concurrencia y Sincronización
1. Suspensión y Reanudación Tema 7: Concurrencia y Sincronización Aplicando estas primitivas a resolver problemas en la vida real: productor/consumidor. 1 2 3 tabla N-1 while(true) { producir_elemento(); if (contador==N) sleep(); almacenar_elemento(); contador++; if (contador==1) wakeup(consumidor); } productor while(true) { if (contador==0) sleep(); retirar_elemento(); contador--; if (contador==(N-1)) wakeup(productor); usar_elemento(); } consumidor Para el diseñador del sistema operativo, perfecto. Pero, ¿nos sirve para resolver problemas? Contar el problema del productor-consumidor. Cuenta que aquí hay dos problemas distintos, uno es el propio acceso al recurso compartido (pueden haber condiciones de carrera al insertar y extraer), pero otro es la coordinación entre procesos cuando estructura de datos se llena o vacía. Nos centraremos en este e ignoraremos el primero. Sigue la traza en la que se produce una conmutación justo tras comprobar valor contador = 0 en consumidor Contar que en los apuntes vienen algunos intentos todos avocados al fracaso, pues estas primitivas adolecen de los problemas que se detallan a continuación. ins ext contador=N contador=0 contador=3 contador=2 contador=1
7
Tema 7: Concurrencia y Sincronización
1. Suspensión y reanudación Tema 7: Concurrencia y Sincronización Problemas: Suspensión es incondicional ¡No hay atomicidad comprobación-acción! Procesos deben conocerse entre sí Un único estado de espera por proceso Procesos están “o despiertos o dormidos” Si proceso está dormido, no hay vinculación alguna con la causa por la que está en dicho estado Aunque no esté en la diapositiva, puedes comentar que en Unix sleep()=pause(), y que wakeup() se puede simular mediante signal();
8
Tema 7: Concurrencia y Sincronización
Índice: Suspensión y Reanudación Semáforos Propiedades y Características de los Semáforos Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización 8
9
Tema 7: Concurrencia y Sincronización
2. Semáforos Tema 7: Concurrencia y Sincronización Concepto de semáforo Implementación de semáforos Semáforos en la práctica Semáforos binarios
10
Tema 7: Concurrencia y Sincronización
2. Semáforos Tema 7: Concurrencia y Sincronización Concepto de semáforo Implementación de semáforos Semáforos en la práctica Semáforos binarios
11
Tema 7: Concurrencia y Sincronización
2.1 Concepto de semáforo Tema 7: Concurrencia y Sincronización E. W. Dijkstra (1.965) Semaforo = tipo abstracto de datos, que encapsula: Un contador entero Una lista de procesos bloqueados en el semáforo Operaciones sobre semáforos: down(s): si contador = 0, proceso se bloquea en semáforo decrementa contador up(s): Incrementa contador Si había algún proceso bloqueado en semáforo, reanuda uno ¡Ambas operaciones son atómicas! Comenta que cuando semáforo = 0 se suele decir que está cerrado, y en caso contrario se suele decir que está abierto Down(s)=P(s), de proberen, probar. Up(s)=V(s), de verhogen, incrementar.
12
Tema 7: Concurrencia y Sincronización
2.1 Concepto de semáforo Tema 7: Concurrencia y Sincronización Utilidad: proteger acceso a recursos compartidos A cada recurso compartido, se asocia semáforo con valor inicial 1. Secciones críticas asociadas al recurso: Protocolo de entrada: down(s) Protocolo de salida: up(s) Ventajas: Robustez Comprobación/Acción son atómicas Procesos que se coordinan no necesitan conocerse entre sí Sólo necesitan conocer semáforos que comparten Flexibilidad Tanto semáforos como recursos compartidos
13
Tema 7: Concurrencia y Sincronización
2. Semáforos Tema 7: Concurrencia y Sincronización Concepto de semáforo Implementación de semáforos Semáforos en la práctica Semáforos binarios
14
Tema 7: Concurrencia y Sincronización
2.2 Implementación de semáforos Tema 7: Concurrencia y Sincronización struct s_semaforo { int contador; listaproc bloqueados; } typedef s_semaforo *semaforo; struct nodoproc { PID proceso; struct nodoproc *sig; } typedef struct nodoproc *listaproc Comenta que estas primitivas están basadas por simplicidad en sleep() y wakeup() En relación con la atomicidad de down y up (click), comenta que lo normal es que implícitamente sean atómicos pues al pertenecer al núcleo del sistema operativo, este no debe ser apropiado por ningún proceso (en dicho caso, getpid() debería dar el PID del proceso que efectuó la llamada. void down(semaforo s) { if (s->contador>0) s->contador--; else { insertar_en_lista (&s->bloqueados, getpid()); sleep(); } } void up(semaforo s) { if (lista_vacia(s->bloqueados)) s->contador++; else { int pid=sacar_de_lista(s->bloqueados); wakeup(pid); } } semaforo CrearSemaforo(int valor); void DestruirSemaforo(semaforo s);
15
Tema 7: Concurrencia y Sincronización
2. Semáforos Tema 7: Concurrencia y Sincronización Concepto de semáforo Implementación de semáforos Semáforos en la práctica Semáforos binarios
16
Tema 7: Concurrencia y Sincronización
2.3 Semáforos en la práctica Tema 7: Concurrencia y Sincronización Productor/Consumidor con semáforos 1 2 3 tabla N-1 while(true) { producir_elemento(); down(vacias); down(excmut); almacenar_elemento(); up(excmut); up(llenas); } productor while(true) { down(llenas); down(excmut); retirar_elemento(); up(excmut); up(vacias); consumir_elemento(); } consumidor Comentar: Nótese que producir_elemento() y consumir_elemento() no pertenecen a sección crítica. ¿Qué ocurriría si se invirtiese orden de dos down() consecutivos (click)? Regla: si tras hacer un down(A) se hace un down(B) (sin haber hecho previamente el up(A), claro), asegúrese de que el proceso que hace up(B) no hace un down(A) previo al up(B). (esto se verá con más detenimiento en capítulo 9). down(excmut); down(vacias); ins ext contador=0 excmut=1 vacias=N llenas=0
17
Tema 7: Concurrencia y Sincronización
2. Semáforos Tema 7: Concurrencia y Sincronización Concepto de semáforo Implementación de semáforos Semáforos en la práctica Semáforos binarios
18
Tema 7: Concurrencia y Sincronización
2.4 Semáforos binarios Tema 7: Concurrencia y Sincronización Caso particular: semáforos con sólo dos estados: Abierto (true, 1, …) Cerrado (false, 0, …) Operaciones sobre semáforos binarios: down(s): si estado=cerrado, proceso se bloquea en semáforo estado=cerrado up(s): estado=abierto Si había algún proceso bloqueado en semáforo, reanuda uno Comenta que en anterior ejemplo, semáforo excmut esencialmente diferente a semáforos llenas y vacias: excmut sólo tiene dos estados, abierto o cerrado. Aclara que “más potente” != “más flexible”. Más potente = “pueden resolver algún problema que no se pueda resolver con binarios”. ¿Son más potentes semáforos contadores que semáforos binarios?
19
Tema 7: Concurrencia y Sincronización
2.4 Semáforos binarios Tema 7: Concurrencia y Sincronización struct s_semaforo { int contador; semaforo_b blqd; /* =abierto */ semaforo_b exc; /* =abierto */ semaforo_b esp; /* =cerrado*/ } typedef s_semaforo *semaforo; void down(semaforo s) { down_b(s->blqd); down_b(s->exc); --(s->contador); if (s->contador >=0) up_b(s->exc); else { up_b(s->exc); down_b(s->esp); } up_b(s->blqd); } contador=contador del semáforo blqd: semáforo que se usa para que sólo pueda haber un proceso haciendo down (garantiza atomicidad del down). exc: semáforo que protege el acceso al contador del semáforo (exclusión mutua en acceso al contador). esp: (truco) se utiliza para simular un sleep(). Inicialmente a 0 con lo que primer down() detiene a proceso. Nota que sólo un proceso se bloquea en este semáforo, los demás esperan a la entrada del down() en el blqd. Nota que blqd garantiza que cuando contador < 0, |contador| = nº de procesos detenidos void up(semaforo s) { down_b(s->exc); ++(s->contador); if (s->contador <=0) up_b(s->esp); up_b(s->exc); }
20
Tema 7: Concurrencia y Sincronización
Índice: Suspensión y Reanudación Semáforos Propiedades y Características de los Semáforos Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización 20
21
Tema 7: Concurrencia y Sincronización
3. Propiedades y Características de los Sem. Tema 7: Concurrencia y Sincronización Reglas generales: Si un semáforo controla sección crítica, Cerrar lo más tarde posible Abrir tan pronto como sea posible Secciones críticas anidadas: Evitar en la medida de lo posible down(a) y despues down(b)→ admisible si proceso que hace up(b) no hace down(a) Al hablar de la selección del proceso que desbloquea up, recuerda comentar que el peligro de usar prioridades es el aplazamiento indefinido. Selección proceso que se desbloquea up: No especificado Depende de implementación: FIFO, aleatorio, prioridad… Los programas nunca deben depender de este detalle!
22
Tema 7: Concurrencia y Sincronización
3. Propiedades y Características de los Sem. Tema 7: Concurrencia y Sincronización Granularidad: nº de recursos controlados por cada semáforo Granularidad fina: un recurso por semáforo Granularidad gruesa: un semáforo para todos los recursos:
23
Tema 7: Concurrencia y Sincronización
3. Propiedades y Características de los Sem. Tema 7: Concurrencia y Sincronización Granularidad fina: Ventajas: mayor grado de paralelismo Granularidad gruesa: (inversa) Inconvenientes: mayor número de semáforos ¡Posibilidad de interbloqueo! P1 P2
24
Tema 7: Concurrencia y Sincronización
Índice: Suspensión y Reanudación Semáforos Propiedades y Características de los Semáforos Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización 24
25
Tema 7: Concurrencia y Sincronización
4. Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización Los Filósofos Comensales void filosofo (int i) { while(true) { pensar(); coger_tenedor(derecho(i)); coger_tenedor(izquierdo(i)); comer(); soltar_tenedor(derecho(i)); soltar_tenedor(izquierdo(i)); } } Comenta primero la historia, y a continuación, la primera solución intuitiva que nos puede llevar al fracaso Comenta que esto es un símil de aquellas situaciones en las que varios procesos tienen que asegurarse la exclusión mutua sobre un conjunto de recurso compartidos. Comer() es la sección crítica. Coger_Tenedor() comprueba si el tenedor está libre, en cuyo caso lo pasa a estado ocupado. Si por el contrario está en estado ocupado, espera hasta que esté libre para marcarlo de nuevo como ocupado. Esto es un ejemplo de interbloqueo con N procesos. Se tratará mejor en capítulo 9. Comenta que hay múltiples estrategias. La que vamos a aplicar consiste en obtener o bien los dos tenedores a la vez, o bien en esperar a que los dos estén libres si uno de ellos no lo está.
26
Tema 7: Concurrencia y Sincronización
4. Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización ¿Una posible solución? void filosofo (int i) { while(true) { pensar(); down (s); coger_tenedor(derecho(i)); coger_tenedor(izquierdo(i)); comer(); soltar_tenedor(derecho(i)); soltar_tenedor(izquierdo(i)); up (s) } } Una primera solución: no es válida, pues no permite la ejecución concurrente de filósofos que no compartan recursos. Sólo un filósofo comiendo en cada instante de tiempo.
27
Tema 7: Concurrencia y Sincronización
4. Problemas Clásicos de Concurrencia Tema 7: Concurrencia y Sincronización f[0] void coger_tenedores(int i) { down(excmut); estado[i]= HAMBRIENTO; probar(i); up(excmut); down(f[i]); } f[N] void soltar_tenedores(int i) { down(excmut); estado[i]= PENSANDO; probar(izquierdo(i)); probar(derecho(i)); up(excmut); } excmut Cada filósofo puede estar en uno de de tres estados: PENSANDO, COMIENDO, HAMBRIENTO Semáforo excmut garantiza exclusión mutua durante los cambios de estado (ojo, sólo en los cambios de estado, es decir, en cada instante de tiempo sólo hay un filósofo cambiando de estado!) Semáforo f[i]: semáforo de espera (para simular un sleep()) Estado[i]: estado de cada filósofo. Observar que rutina probar() tiene doble uso: Si invocada por un rutina coger_tenedores() (filósofo que quiere comer) abre o deja cerrado su semáforo de espera, en función de que pueda comer o no. No espera directamente pues en ese momento se tiene cerrada la exclusión mutua. Si invocada por rutina soltar tenedores por un filósofo sobre los filosófos vecinos, lo que hace es dar la oportunidad de comer a aquellos filósofos vecinos que deseen comer (simula que el filósofo reintenta la operación probar()). f[1] f[3] void filosofo (int i) { while(true) { pensar(); coger_tenedores(i); comer(); soltar_tenedores(i); } } f[2] void probar (int i) { if ((estado[i]==HAMBRIENTO) && (estado[izquierdo(i) != COMIENDO) && (estado[derecho(i)] != COMIENDO) { estado[i]= COMIENDO; up(f[i]) } }
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.