Cuando varios Sistemas Operativos/Procesos o Sistemas Operativos/Hilos comparten datos, surge la necesidad de comunicación entre procesos (IPC) y de sincronizarlos. Tanenbaum identifica tres problemas: cómo pasar información, cómo evitar que se estorben y cómo ordenar correctamente sus acciones.
Una condición de carrera (race condition) ocurre cuando dos o más procesos leen o escriben datos compartidos y el resultado final depende del orden exacto de ejecución.
Ejemplo del spooler de impresión: dos procesos A y B leen in = 7 (siguiente ranura libre). A es interrumpido antes de actualizar in; B escribe su archivo en la ranura 7 y pone in = 8; A reanuda, escribe también en la ranura 7 y pone in = 8. El trabajo de B se pierde y nadie se entera.
La región crítica (o sección crítica) es la parte del programa donde se accede a memoria compartida. Para evitar carreras hace falta exclusión mutua. Una buena solución debe cumplir cuatro condiciones:
Sencillo en monoprocesador, pero peligroso dar ese poder a procesos de usuario y no funciona en multiprocesadores. Útil sólo dentro del Sistemas Operativos/Kernel.
Un simple lock = 0/1 tiene la misma condición de carrera que pretende resolver.
/* Proceso 0 */ /* Proceso 1 */
while (TRUE) { while (TRUE) {
while (turn != 0) ; while (turn != 1) ;
critical_region(); critical_region();
turn = 1; turn = 0;
noncritical_region(); noncritical_region();
} }
Viola la condición 3: un proceso lento fuera de su región crítica bloquea al otro. Una variable que se consulta en bucle es un spin lock.
int turn;
int interested[2];
void enter_region(int process) {
int other = 1 - process;
interested[process] = TRUE;
turn = process;
while (turn == process && interested[other] == TRUE) ;
}
void leave_region(int process) {
interested[process] = FALSE;
}
Soporte de hardware: TSL REGISTER,LOCK lee la palabra LOCK en un registro y guarda un valor distinto de cero, de forma atómica (bloquea el bus de memoria). XCHG en x86 es equivalente.
enter_region:
TSL REGISTER,LOCK | copia lock al registro y pone lock a 1
CMP REGISTER,0 | ¿era cero?
JNE enter_region | si no, el candado estaba puesto: repetir
RET
leave_region:
MOVE LOCK,0
RET
Desperdicia CPU y sufre el problema de inversión de prioridades: un proceso H de alta prioridad hace espera ocupada mientras L, de baja prioridad, tiene el candado pero nunca es planificado.
La alternativa es dormir y despertar (sleep/wakeup), que lleva a los Sistemas Operativos/Semáforos y a los Sistemas Operativos/Mutex y monitores.
send(destino, &mensaje) y receive(origen, &mensaje). Funciona entre máquinas.Ver Sistemas Operativos/Problemas clásicos de IPC e Sistemas Operativos/Interbloqueos.