950 likes | 1.13k Views
sisOpe Temario Curso: 14/15. Horas INTRODUCCIÓN 4 PROCESOS Y THREADS 10 GESTIÓN DE MEMORIA 8 ENTRADA / SALIDA 2 SISTEMA DE FICHEROS 6. sisOpe 2. Procesos y Threads Curso: 14/15. Introducción Procesos Visión abstracta Esbozo de implementación Threads (Procesos ligeros)
E N D
sisOpe Temario Curso: 14/15 • Horas • INTRODUCCIÓN 4 • PROCESOS Y THREADS 10 • GESTIÓN DE MEMORIA 8 • ENTRADA / SALIDA 2 • SISTEMA DE FICHEROS 6
sisOpe 2. Procesos y Threads Curso: 14/15 • Introducción • Procesos • Visión abstracta • Esbozo de implementación • Threads (Procesos ligeros) • Comunicación entre procesos • Condición de carrera • Exclusión mutua y región crítica • Implementación de la exclusión mutua • Paso de mensajes • Planificación de procesos • Criterios • Políticas • Sistemas multiprocesador
T3 T3 CPU2 T2 T2 CPU1 T1 T1 t t 18 13 INTRODUCCIÓN Interesa tener máquinas que ejecuten varios procesos al mismo tiempo Aprovechar tiempos muertos E/S Soluciones elegantes concurrentes Más rapidez con más de una CPU pseudoparalelismo Con multiprocesadores también interesa multiplexar las CPU’s
Procesos independientes: La “shell” crea un proceso para ejecutar un programa de usuario “ls” P • Debe cargarse el ejecutable en memoria shell ls H ls.exe • Dotarle de registros, pila, etc. • Procesos cooperantes: Un servidor Web crea un proceso para atender una petición de un cliente P H web • Dotarle de registros, pila, etc. PROCESOS (Visión abstracta: Recordar sus llamadas) Dos relaciones típicas entre proceso Padre y proceso Hijo: ¿fork + exec? ¿fork? • El código ya está en memoria Parecido a Threads
/etc/inittab id:rlevel:action:process P1 putty /etc/rc5.d login as: Password: login /etc/rc.d/rc 5 P2 P3 P5 xinetd /etc/passwd P6 P4 P7 bash pcarazo:........:/bin/bash Red ? grupo de procesos PROCESOS (Visión abstracta: Recordar sus llamadas) Proceso de arranque y grupos de procesos init gdm login PC1> rlevel 0 Halt 1 Monousuario 2 MultiSinRed 3 MultiConRed 5 X11 6 Reboot
¿Cómo es elciclo de vidade un proceso? CPU Creación Terminación P3 P4 P1 P2 P3 P1 P2 P3 P1 P4 P3 P3 P2 P1 Expulsión P1 • EnEjecución • Preparado • EnEspera o Bloqueado Activo P2 Ejecu. P4 Prep. Espera Esbozo de implementación P3 P4 ¿P4 read(cinta, ) ¿P1 fin E/S? ¿P3 mucha CPU? ¿P2.sleep(5 )? ¿P1.read(disco, )? ¿P3 termina? ¿Estados de un proceso?
forkp EnEjecución exit wait exit forkh ¿forkh? Preparado EnEspera exit Diagrama de transición de estados de un Proceso F.R. wait F.R. sleep wait sleep F.R. ¿forkp? F.R.
El contexto de un proceso está distribuido en varias zonas • Contexto de memoria (Código y Datos) MP/MSec • Bloque de control (descriptor) del Proceso MP (S.O.) • Contexto del procesador Reg/MP/MSec MP Ejecutándose MSec CPU pila S.O. Bloqueado Esbozo de implementación en términos más informáticos
type descriptorProceso is record pid: ----------; --------------- end record; 584 procesos : array[1..maxProcesos] of descriptorProceso; 1 2 3 4 97 98 99 100 50 Esbozo de implementación ( ¿Cuántos procesos? ) ¿#Procesos ilimitado o un máximo predeterminado? maxProcesos: constant:=100; Reservado type idProceso isNATURALrange0..maxProcesos; ¿Correcto? ejecutandose : idProceso;
1..100 Mejor espaciar más los códigos pid: NATURAL; 1..65535... 0 Descriptor libre Algo más complejo dar PID’s 1 2 3 4 97 98 99 100 50 Esbozo de implementación ( ¿Cómo dar los PID’s? ) type descriptorProceso is record pid: idProceso; --------------- end record; ¿Problemas? • 99 procesos en el sistema • Hago ps y veo un proceso mío (57) • Me dispongo a kill–9 57 • Mi proceso termina antes del kill y se crea otro proceso con el código 57 ¡ Mato a otro proceso ! ¿ejecutandose?
Esbozo de implementación ( ¿Estados y su gestión? ) type unEstado is (ejecutandose, preparado, espLapso, espFinHijo, zoombie);
type descriptorProceso is record pid: NATURAL; estado: unEstado; end record; sig: IdProceso; type unaCola is record primero: idProceso := 0; ultimo: idProceso:= 0; end record; preparados: unaCola; ejecutandose: idProceso; 1 2 3 4 97 98 99 100 50 Esbozo de implementación ( ¿Estados y su gestión? ) type unEstado is (ejecutandose, preparado, espLapso, espFinHijo, zoombie); CPU queda libre. ¿A qué Pi se la doy? • Recorro procesos buscando uno que esté preparado Lento e injusto • Si decido elegir al Pi que lleva más tiempo preparado, lo mejor cola FIFO
type descriptorProceso is record pid: NATURAL; estado: unEstado; sig: idProceso; lapso: NATURAL; end record; espLapso : unaCola; 4 97 50 1 2 3 4 97 98 99 100 50 5 25 5 5 15 10 Esbozo de implementación ( ¿Procesos bloqueados? ) espLapso => Muy parecido a preparados, sólo que es necesario indicar cuándo despertarles o cuánto falta para despertarles, ... • El campo sig me sigue sirviendo para encadenar • Otras formas de implementarlo:
Esbozo de implementación ( ¿Procesos bloqueados? ) espFinHijo => El fin de un hijo sólo puede estar esperándolo su Padre. Puede no ser necesaria una cola. type descriptorProceso is record pid: NATURAL; padre: idProceso; estado: unEstado; sig: idProceso; lapso: NATURAL; end record; • El Padre (P) hace wait (H): -- Localizar H en procesos => h ifh.estado = zoombie then Liberar recursos del Hijo y continuar al Padre else -- hijo vivo p.estado:=espFinHijo; p.sig:=h; liberar CPU; • Un Hijo(H) termina exit: If (p.estado = espFinHijo) & (p.sig = h) then liberar recursos Hijo y continuar Padre else h.estado := zoombie y liberar CPU
Esbozo de implementación ( Concluyendo ) maxProcesos : constant := 100; type idProceso is NATURAL range 0..maxProcesos; type unEstado is (ejecutandose, preparado, espLapso, espFinHijo, zoombie); type descriptorProceso is record pid: NATURAL; padre: idProceso; estado: unEstado; sig: idProceso; lapso: NATURAL; SP: address; memoria: ----------; ficheros: ----------; tiempos: ----------; end record; ¿ fork y exec ? type unaCola is record primero: idProceso := 0; ultimo: idProceso := 0; end record; procesos : array [1..maxProcesos] of descriptorProceso; ejecutandose: idProceso; preparados, espLapso: unaCola;
Esbozo de implementación ( Otro ejemplo ) Campos en una entrada a la tabla de procesos
Llamada al Sistema • Fin de Proceso • Bien/Mal • Interrupción Trap Mecanismo similar (E/S, F.R.) Hw Ens. C/Modula/Ada Ens. ejecu- tándose Pi S.O. Pj Planificador (1) (2) (3) (4) Dispatcher Esbozo de implementación ( El Cambio de Contexto ) Causas? Supongamos como causa “Fin de Rodaja” ¿No hay procesos preparados? (1) Reconocimiento de la interrupción (3) 1 Recorrer dormitorio 2 Elegir siguiente proceso (2) Salvar reg (Pi) y conmutar de pila (4) Recuperar reg (Pj) y cederle control
Vector de Interrupciones S.O. DIV 0 INT 3 ------- ------- ------- ------- ------- ------- ------- ------- TRAP #0 Cambio de contexto Se salva el SR y PC Esbozo de implementación ( El Cambio de Contexto ) ---------- divu d5,d0 ---------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ---------- ---------- sleep(10) ---------- ---------- exit(0) ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- ------- -------
Pi Pj Registros Código Datos, Pila Ficheros Registros Código Datos, Pila Ficheros fork exec ls.exe Threads ( Visión abstracta ) Modelo de procesos más común Espacios de direcciones disjuntos • Facilita protección PiPj, pero: • Creación laboriosa • Cambio de contexto pesado • (procesador + entorno) TLB’s, cachés, ... • Comunicación vía mensajes • más seguro pero más lento ¿Y si los procesos son cooperantes? • Objetivo común • Colaboración vs agresión • Protección más laxa • Pueden desear mantener datos comunes con los menores costes de tiempo
Ti Tj Registros Pila Registros Pila C1 consulta Código, Datos Ficheros C2 alta S consulta Cn petición petición petición BD utilidades Threads ( Visión abstracta ) Procesos Ligeros Espacios de direcciones no disjuntos Servidor de localización de utilidades ¡ Muy eficaz con multiprocesadores ! • Soportados de dos formas: • En el espacio del S.O. • En el espacio del Usuario respuesta Biblioteca
Como fork sólo que crea un Thread “Específico de Linux” Thread soportado como tal por el S.O. (no portable) Biblioteca pthread (API POSIX 1003.1c) Threads ( “Linux” ) int__clone (int (*fn) (void *arg), void *child_stack, int flags, void *arg) intpthread_create (pthread_t * thread, atributos, funcion, argumentos) pthread_tpthread_self (void) intpthread_exit (void *estado) intpthread_join (pthread_t thread, void **estado) ................................................... ................................................... ¿ fork + threads ?
Threads ( Ejemplos de uso: tonto.c ) #include <pthread.h> #include <stdio.h> int main (int argc, char *argv[]){ pthread_t tA, tB; int datoA=0; datoB=0; pthread_create(&tA, NULL, A, NULL); pthread_create(&tB, NULL, B, NULL); pthread_join (tA, NULL); pthread_join (tB, NULL); exit (0); } void *A (void *basura) { datoA = 1000; sleep (5); printf (“datoB=%d\n”, datoB); pthread_exit (NULL); } void *B (void *basura) { datoB = 2000; sleep (5); printf (“datoA=%d\n”, datoA); pthread_exit (NULL); }
Threads ( Ejemplos de uso: cuentaPar.c ) • cuentaPar.c: Número de apariciones de un número en un vector 6 2 0 7 4 9 3 4 9 8 0 6 7 9 6 0 6 7 9 8 6 2 5 2 6 4 7 9 3 5 2 1 7 3 2 66 4 4 0 T0 T1 T2 T3 1 3 2 2 + const N = 40; objetivo = 6; numCPUs = 4; var vector array[1..N] of integer; 8 ¿ Algoritmo paralelo ?
Threads ( Ejemplos de uso: cuentaPar.c ) int longRodaja, numVecesLocal[MAX_ESCLAVOS], *vector; void *esclavo (void *parametro) { ..... } int main (int argc, char *argv[]) { int i, numVeces, cardinalidad = atoi (argv[1]); int numEsclavos = atoi (argv[2]); pthread_tpids[MAX_ESCLAVOS]; // Pedir memoria e inicializar vector // Crear esclavos y esperar a que terminen su trabajo for (i = 0; i < numEsclavos; i++) pthread_create(&pids[i], NULL, esclavo, (void *) i); for (i = 0; i < numEsclavos; i++) pthread_join(pids[i], NULL); // Sumar los valores de todos e informar del resultado numVeces = numVecesLocal[0]; for (i = 1; i < numEsclavos; i++) numVeces = numVeces + numVecesLocal[i]; printf (“Veces que aparece = %d\n”, numVeces); } %cuentaPar 1000000 4
Threads ( Ejemplos de uso: cuentaPar.c ) // Variables globales int longRodaja, numVecesLocal[MAX_ESCLAVOS], *vector; void *esclavo (void *parametro) { int yo, inicio, fin, i, j, numVeces; yo = (int) parametro; inicio = yo * longRodaja; fin = inicio + longRodaja; // Buscar en mi parte del vector numVeces = 0; for (i = inicio, i < fin; i++) if (vector[i] == NUM_BUSCADO) numVeces++; numVecesLocal[yo] = numVeces; pthread_exit(NULL); }
Threads ( Ejemplos de uso: cuentaPar.c ) cuentaPar 400.000.000 1..8 // Recorriéndolo diez veces 4 2 1 8 7 Esclavos 6 5 1,113 Tiempo 1,408 2,721 1,127 1,286 5,480 0,998 4,86 Aceleración 4,92 5,49 4,26 3,89 2,01 0,81 0,85 Eficiencia 1,01 0,69 0,97 0,70 2 Xeon E5520 Quad 2,26GHz• 8ML3 •12GB • 500GB
Threads ( Ejemplos de uso: sortPar.c ) • sortPar.c: Ordenar un vector en memoria 3 8 15 2 4 1 7 10 6 14 13 5 11 9 12 16 ordenar T3 T0 T1 T2 T0 T2 T0 2 3 8 15 1 4 7 10 5 6 13 14 9 11 12 16 mezclar 1 2 3 4 7 8 10 15 5 6 9 11 12 13 14 16 mezclar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Threads ( Ejemplos de uso: sortPar.c ) • sortPar.c: Ordenar un vector en memoria [Refinamiento] Va ? esclavo (yo: integer); ordenarRodaja(yo); case yo of 0: mezclar(A,B,E); mezclar(E,F,G); 1: ; 2: mezclar(C,D,F); 3: ; end; 0 1 2 3 Va A B C D 0 2 Vb E F 0 Va G La mezcla es destructiva => vector auxiliar • sem_init • sem_wait • sem_post • Mezclar requiere haber ordenado … => semáforos
Threads ( Ejemplos de uso: sortPar.c ) #define MAX_ENTERO 10000 #define MAX_ESCLAVOS 4 // Solo funciona con 4 esclavos //-------------- VARIABLES GLOBALES ------------------------------- intcardinalidad, longRodaja; int*vector, *vectorBis; sem_tS1a0, S3a2, S2a0; voidimprimir (int*vector) { inti; printf("Contenidodelvector\n"); printf("====================\n"); for(i=0; i<cardinalidad; i++) { printf("%6d ", vector[i]); if((i%10) == 0)printf("\n"); } printf("\n"); } voidmezclar (inti,intlongRodaja, int*vOrg, int*vDst) { intiDst, iTope, j, jTope; iTope = i + longRodaja; j = iTope; jTope = j + longRodaja; for(iDst = i; iDst < jTope; iDst++) { if(i == iTope ) vDst[iDst] = vOrg[j++]; elseif(j == jTope ) vDst[iDst] = vOrg[i++]; elseif(vOrg[i] < vOrg[j]) vDst[iDst] = vOrg[i++]; elsevDst[iDst] = vOrg[j++]; } }
Threads ( Ejemplos de uso: sortPar.c ) void*esclavo(void*parametro) { intyo, inicio, fin, i, j, imenor, menor; intunCuarto, unMedio; yo = (int) parametro; inicio = yo * longRodaja; fin = inicio + longRodaja; unMedio = cardinalidad / 2; unCuarto = cardinalidad / 4; // Ordenar por inserciondirecta for(i = inicio; i < fin; i++) { imenor = i; menor = vector[i]; for(j = i; j < fin; j++) if(vector[j] < menor) { imenor = j; menor = vector[j]; } vector[imenor] = vector[i]; vector[i] = menor; } // Fase de mezclas. Solo valida para 4 esclavos switch(yo) { case0:sem_wait(&S1a0); mezclar(0, unCuarto, vector, vectorBis); sem_wait(&S2a0); mezclar(0, unMedio, vectorBis, vector); break; case1: sem_post(&S1a0); break; case2:sem_wait(&S3a2); mezclar(unMedio, unCuarto, vector, vectorBis); sem_post(&S2a0); break; case3:sem_post(&S3a2); break; default:printf("Error\n"); break; } pthread_exit(NULL); }
Threads ( Ejemplos de uso: sortPar.c ) intmain( intargc, char *argv[] ) { inti, numEsclavos; pthread_tpids[MAX_ESCLAVOS]; cardinalidad = atoi(argv[1]); numEsclavos = MAX_ESCLAVOS; longRodaja = cardinalidad / numEsclavos; // Pedir memoria e inicializar elvector vector = malloc(cardinalidad * sizeof(int)); vectorBis =malloc(cardinalidad *sizeof(int)); for(i=0; i<cardinalidad; i++) vector[i] = random() % MAX_ENTERO; imprimir(vector); // Inicializar semaforos para sincronizar sem_init(&S1a0, 0, 0); sem_init(&S3a2, 0, 0); sem_init(&S2a0, 0, 0); // Crearesclavos y esperar a que terminensutrabajo for(i=0; i<numEsclavos; i++) pthread_create(&pids[i], NULL, esclavo, (void*) i); for(i=0; i<numEsclavos; i++) pthread_join(pids[i], NULL); imprimir(vector); return(0); } sort 200000 => 8:350 sortPar 200000 => 2:100
El S.O. no los soporta • Cambio contexto rápido • Distintos planificadores • read, … ¡ Bloqueantes ! • Falta de página • ¡Planificación expulsora! Threads ( En el espacio de usuario ) pthread_create pthread_join pthread_exit pthread_self
? Threads ( En el espacio del S.O. )
Canal de Panamá Comunicación entre Procesos Los procesos cooperantes necesitan mecanismos para sincronizarse y comunicarse información de forma segura Sincronización Ordenación temporal de la ejecución de procesos A antes que B Tortilla de patatas Batir Pelar Pelar Huevos Cebollas Patatas Mezclar, Añadir Sal y Freir Comunicación Paso de información entre tareas Síncrona o Asíncrona Filtros Unix: who|wc|sed -e ‘s/ [ ]*/:/g’ |cut -d: -f2
¡Me tangan! ¡Que buen negocio! Condiciones de Carrera • La falta de sincronismo entre procesos cooperantes da problemas • Canal de Panamá Barco encallado • Tortilla de Patatas No hay quien se la coma • Uso de datos / recursos comunes Inconsistencia El empresario y los taxistas:
+ 161347 Condiciones de Carrera (Modelización con threads) int cuenta; void *taxista(void *parametro) { ..... } intmain( intargc, char *argv[] ) { int i, numEsclavos; pthread_tpids[MAX_ESCLAVOS]; numEsclavos = atoi(argv[1]); cuenta = 0; // Crear esclavos y esperar a que terminen su trabajo for (i=0; i<numEsclavos; i++) pthread_create (&pids[i], NULL, taxista, (void *) i); for (i=0; i<numEsclavos; i++) pthread_join (pids[i], NULL); printf ("Total recaudacion = %d\n", cuenta); return (0); } Ingreso de Taxista 1 = 80729 Ingreso de Taxista 2 = 80618 Total recaudacion = 161096
Hacer Carrera Ingreso Condiciones de Carrera (Modelización con threads) void*taxista (void *parametro) { // Variables recaudacion = 0; mio = 0; do { espera = random() % MAX_ESPERA; for (i=1; i<espera; i++); importe := random (maxImporte); mio := mio + (importe / RATIO_TAXISTA); cuenta := cuenta + importe – (importe / RATIO_TAXISTA); recaudacion := recaudacion + importe }while(mio < SUELDO_DIA); printf (“Ingreso de Taxista %d = %d\n”, yo, recaudacion – mio); pthread_exit(NULL); } Buscar Cliente
Condiciones de Carrera (Modelización con threads) Fallos x 1.000 pc9:8Cores Threads pc1:4Cores 2 7 207 4 64 926 8 230 1.000 16 533 1.000 32 830 1.000
T1.importe 3.1: PUSH importe 3.2: PUSH cuenta 3.3: ADDP 3.4: POP cuenta T2.importe 10.000 1.500 T2.SP T1.SP 3.3 3.3 5.000 5.000 1.500 10.000 15.000 6.500 T2 T1 cuenta cuenta cuenta 5.000 15.000 6.500 Condiciones de Carrera (El problema) 3: cuenta := cuenta + importe ¿problema? 3.1, 3.2 3.3, 3.4 3.1, 3.2 3.3, 3.4
Integridad Datos Comunes RC Aquí cero, uno o más Pi Aquí como máximo un Pi Exclusión Mutua RC Exclusión mutua y Región crítica (La solución) Los Pi indicarán cuándo EntranEnRC y cuándo SalenDeRC
Exclusión mutua y Región crítica (La solución) EntrarEnRC; cuenta := cuenta + importe – (importe div ratioTaxista); SalirDeRC; • REQUISITOS • En una mismaRegión Crítica no más de un proceso • Sin supuestos: #µP, #Pi, velocidades relativas, ..... • Ningún Pi fuera de su Región Crítica bloqueará a otros Pj • Decisión de quién entra a una Región Crítica en un tiempo finito
Hw Sw S.O. Lenguaje Implementación de la Exclusión Mutua • Mecanismos: • Inhibición de interrupciones • Semáforos • Cerrojos (espera activa) • Monitores Inhibición de interrupciones DirecciónGeneralDeTráfico repeat aguardarAgazapados y ¡foto! InhibirInterrupciones numeroMultas++ PermitirInterrupciones untilcubiertoCupo Taxistas InhibirInterrupciones cuenta := cuenta + importe PermitirInterrupciones • RC muy corta o pueden perderse interrupciones • Exclusión total vs parcial • Sólo válido en monoprocesador • Peligroso en manos del usuario • Útil dentro del propio S.O.
Taxistas Entrar (RCTaxistas) cuenta := cuenta + importe Salir (RCTaxistas) Guardia Civil Entrar (RCDGT) numeroMultas++ Salir (RCDGT) entrar tst.b RCT bnz entrar move.b #$FF,RCT push importe push cuenta addp pop cuenta salir move.b #$00,RCT RCT dc.b 0 while RCT = ocupada do null; RCT := ocupada cuenta := cuenta + importe; RCT := libre Implementación de la Exclusión Mutua ( Cerrojos ) Una variable “cerrojo” por cada RC distinta que indica Libre/Ocupada ¡ No funciona !
RCT RCT FF FF RCT 00 T2 T1 T1.SR Z T2 dentro RCT 1 Implementación de la Exclusión Mutua ( El cerrojo falla ) ---------------- ---------------- entrar tst.b RCT bnz entrar move.b #$FF,RCT ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- tst.b RCT bnz entrar move.b #$FF,RCT ---------------- ---------------- ¡¡ T1 también dentro RCT !!
El Hw ayuda con una instrucción atómica que consulta y cambia valor tst.b cerrojo move.b valor,cerrojo tas.b cerrojo, valor entrar tas.b RCT,#$FF bnz entrar push importe push cuenta addp pop cuenta salir move.b #$00,RCT RCT dc.b 0 F.R. ¡SI! • No funciona en multiprocesador ya que TAS es ininterrumpible dentro de un procesador, pero supone dos accesos al bus: • 1 Lectura del cerrojo • 2 Modificación del cerrojo Implementación de la Exclusión Mutua ( Un cerrojo seguro? ) Algoritmos: Dekker, Dijkstra, Knuth, Peterson, ....... ¿Habrá problemas?
RCT RCT RCT FF FF FF RCT 00 tas.b RCT,#$FF bnz entrar T1.SR Z 1 Implementación de la Exclusión Mutua ( Un cerrojo seguro! ) T2 T1 ---------------- ---------------- tas.b RCT,#$FF ---------------- ---------------- tas.b RCT,#$FF bnz entrar bnz entrar ------------- ------------- ------------- ------------- T2 no puede entrar en RC mientras está T1 T1 en RCT
P1 P2 P1 T1 PB, L1, PB, E1 P2 T2 PB, L2, PB, E2 ??? RCT PL PH L2, E2, L1, E1 T2 T1 L1, E1, L2, E2 T1 T2 L1, L2, E1, E2 T1 T2 deadLock ( El Hw nos ayuda ) TASL“TAS with Lock” BusLock, Leer, Escribir, BusRelease Implementación de la Exclusión Mutua ( TAS todavía falla! ) TAS PedirBus, Leer, PedirBus, Escribir tas.b RCT,#$FF bnz entrar tasl.b RCT,#$FF bnz entrar --------------------- --------------------- • ¡ Todavía dos problemas ! • Espera Activa • Inversión de prioridades ¿ Qué hacer ?
Multiprocesador ? RCT Pi Pj F Implementación de la Exclusión Mutua ( RC POSIX ) int pthread_mutex_lock(pthread_mutex_t *regionCritica) int pthread_mutex_unlock (pthread_mutex_t *regionCritica) ¿Posible implementación (sin espera activa)? lock (RCT): inhibir interrupciones salvarEstado(ejecutandose) if RCT.libre then RCT.libre = FALSE else meter (ejecutandose, RCT); ejecutandose = planificar(); recuperarEstado(ejecutandose) rte /*Se habilitan interrupciones*/ type pthread_mutext_t is record libre : BOOLEAN; cola : unaCola; end record; tasl ¡ Ojo !
Operaciones Atómicas Implementación de la Exclusión Mutua ( Semáforos ) Soportado por el S.O. garantiza exclusión mutua sin espera activa type Semaforos is private; Inicializar (S: Semaforos; Valor: NATURAL); Bajar (S); -- Puede bloquear al proceso (Si Valor = 0) Subir (S); -- Puede desbloquear a UN proceso Dar soporte a RC con semáforos es fácil: Inicializar (S_RCT, 1) Inicializar (S_RCGC, 1) --------------- --------------- Bajar (S_RCT) Bajar (S_RCGC) Cuenta := Cuenta + Importe numeroMultas++ Subir (S_RCT) Subir (S_RCGC) --------------- ---------------