Está en la página 1de 37

Sincronizacin

Cecilia Hernndez

Motivacin

Hebras realizan trabajo en conjunto en una aplicacin multihebra Uno espera resultados determinsticos (ante una misma entrada obtener misma salida) Si no hay comparticin de datos entre hebras

Resultados de ejecucin no dependen de planificacin (ej. Multiplicacin de matrices)

Comparten recursos como memoria mediante acceso a estructuras de datos compartidas

Operaciones sobre cuenta bancaria (depositar, girar)

Coordinan su ejecucin
Ejemplo, productores que generan informacin que pasan a consumidores que consumen informacin

Motivacin

Por qu se comparte?

Costo

Comprar M recursos, amortizar costo permitiendo compartir a N (N > M)

Una impresora con muchos archivos, una carretera con muchos autos, un multicore con muchos procesos

Informacin

Una hebra puede necesitar los datos generados por otra Mejora tiempo de ejecucin Proporciona modularidad, tareas separadas por actividades las que se comunican slo cuando es necesario

Motivacin

Qu problemas puede traer la ejecucin concurrente/paralela de procesos o hebras?


Posibles inconsistencias Y esto es producto de qu?

Cmo podemos manejar la concurrencia/paralelismo de acuerdo a lo que nuestra aplicacin necesita?

Explotar concurrencia/paralelismo, pero respetando puntos de conflictos o determinados rdenes de ejecucin

Posibles inconsistencias

Necesario saber que ocurre en el HW

Ejemplo: en C la instrucciones x++ y x-- ejecutadas concurrentemente por dos hebras

Qu puede pasar con el valor final de X ?


H1 H2 R2 = X R2 = R2 - 1 X = R2 Secuencial X=6 R1 = X R1 = R1 + 1 X = R1 R2 = X R2 = R2 - 1 X = R2 X=6

R1 = X R1 = R1 + 1 X = R1

Posibles inconsistencias
H1 X=6 R1 = X R1 = R1 + 1 Cambio contexto R2 = X R2 = R2 - 1 Cambio contexto X = R1 Cambio contexto X = R2 X=7 X=5 H2 X=6

Sincronizacin

Por correctitud, es necesario el control de la cooperacin y acceso a recursos compartidos

El nico supuesto vlido es que hebras ejecutan sus instrucciones en forma entrelazada

SOs modernos son apropiativos Mquinas actuales son multicore No se pueden asumir tiempos de ejecucin (nunca usar sleep(n) para demorar la ejecucin entre hebras)

Algunas aplicaciones requieren patrones de ejecucin con concurrencia y dependencia de orden de ejecucin Control de cooperacin se realiza mediante mecanismos de sincronizacin Sincronizacin tambin se aplica a procesos (no slo hebras) y a procesos en un sistema distribuido

Comparticin de recursos

Problema bsico

Hebras accesan a recurso compartido


Cules son en hebras?, en procesos? Si variables se leen, modifican, escriben concurrentemente entonces su acceso debe realizarse en forma controlada

Si no, pueden ocurrir resultados inesperados

Veremos

Mecanismos para controlar acceso a recursos compartidos

Locks, mutexes, variables de condicin, semforos y monitores Productores/consumidores, lectores/escritores, filsofos comensales

Algunos patrones tpicos

Ejemplo clsico

Cuenta bancaria con operaciones de Depositar(), Girar(), Balance()


int Girar(Cuenta c1, int cantidad) { int balance = get_balance(c1); balance -= cantidad; set_balance(c1, balance); return balance; }

Ejemplo clsico

Qu pasa si tiene cuenta compartida con su mam (con saldo $1000) y ambos van a 2 cajeros a Girar(100) concurrentemente

int Girar(Cuenta c, int cantidad) { int balance = get_balance(c); balance -= cantidad; set_balance(c, balance); return balance; }

int Girar(Cuenta c, int cantidad) { int balance = get_balance(c); balance -= cantidad; set_balance(c, balance); return balance; }

Ejemplo clsico
balance = get_balance(c, cantidad); balance -= cantidad; Cambio contexto balance = get_balance(c, cantidad); balance -= cantidad; set_balance(c, balance); Cambio contexto set_balance(c, balance);

Quin gana, su cuenta o el banco? Identifique que entrelado proporcionara resultados correctos y cules no.

Cul es el problema?

Comparticin de variables compartidas sin mecanismo de control para evitar inconsistencias

Detectar estos problemas es muy difcil porque no se reproducen fcilmente Estos problemas se llaman condiciones de carrera Variables globales y memoria dinmica Archivos, puertos de conexin

Qu recursos son compartidos en hebras?

Qu recursos son compartidos en procesos?

Cmo resolver problemas?


Usando mecanismos de sincronizacin Idea es controlar acceso a recursos compartidos haciendo que slo una hebra a la vez pueda accesar recurso compartido

Se llama exclusin mutua Segmento de cdigo que accesa a recurso compartido se llama seccin crtica Idea es que slo se proteja seccin crtica y no otro cdigo

Definiciones

Condicin de carrera

Salida de programa concurrente depende del orden en que se ejecutan las instrucciones produciendo inconsistencias Slo una hebra a la vez puede accesar recurso compartido Segmento de cdigo que slo una hebra a la vez puede ejecutar Primitiva bsica para asegurar exclusin mutua, asegurando que slo una hebra a la vez pueda accesar a seccin crtica

Exclusin mutua

Seccin crtica

Lock

Requerimientos de secciones crticas

Exclusin mutua Progreso

Si una hebra no est en seccin crtica no debe impedir que otra que quiera entrar entre Si una hebra est esperando entrar a seccin crtica eventualmente debe tener xito La sobrecarga de uso de sincronizacin debe ser mucho menor que el tiempo de ejecucin de seccin crtica

Espera finita

Eficiencia

Mecanismos de sincronizacin

Locks

Semntica mnima, sirven para construir otros mecanismos mas complejos Idea basada en la idea que hebra debe esperar (wait) por la ocurrencia de un evento antes de seguir, para ello otra hebra le avisar cuando eso ocurra (signal) Bsicos, accesibles en SOs (llamado a sistema semget() en linux) Fcil de cometer errores Alto nivel, requiere soporte del lenguaje de programacin Ms modular que semforos, en java se usa synchronized como base para construirlos Modelo simple de comunicacin y sincronizacin basado en transferencia de datos atmica a travs de un canal Aplicacin directa a sistemas distribuidos (RPC, Java RMI)

Variables de condicin

Semforos

Monitores

Mensajes

Locks

Lock: objeto en memoria que proporciona las siguientes operaciones

acquire()/lock(): Hebra la llama antes de entrar a S.C.

No retorna hasta que hebra consigue lock

release()/unlock(): Hebra la llama despus de salir de S.C. Entre que se llama acquire y release hebra mantiene el lock Qu pasa si acquire()/release() no se usan en pares? Spinlocks (no bloqueante, espera ocupada (busy-waiting)) Mutex (bloqueante)

Exclusin mutua dado por par de llamados acquire(), release()


2 tipos de locks

Using locks
H1 X++; H1 acquire(lock) R1 = X R1 = R1 + 1 X = R1 realease(lock) acquire(lock) R1 = X R1 = R1 + 1 acquire(lock) X = R1 release(lock) R2 = X R2 = R2 1 X = R2 release(lock) H2 X--; H2 acquire(lock) R2 = X R2 = R2 1 X = R2 realease(lock)

Que pasa aqu? - locks - estado hebras

Using locks

int Girar(Cuenta c, int cantidad) { int balance = get_balance(c); balance -= cantidad; set_balance(c, balance); return balance; }

int Girar(Cuenta c, int cantidad) { int balance = get_balance(c); balance -= cantidad; set_balance(c, balance); return balance; }

Use locks para evitar condicin de carrera Cules son las secciones crticas? Secuencia de operaciones y estados

Lock: acquire/release

acquire(lock)

Seccin crtica

release(lock)

Spinlocks

Cmo implementar locks


Lock_t L = true; void acquire(Lock_t &L){ While(!L); L = false; } void release(Lock_t &L){ L = false; }

Donde est la busy-waiting? Funciona implementacin?

Implementacin de locks

Operaciones acquire/release deben ser atmicas


Cdigo se ejecuta todo o nada Atmico : no puede ser interrumpido

HW debe ayudar para poder implementar operaciones atmicas

Deshabilitar/habilitar interrupciones

Para evitar cambios de contexto

Instrucciones atmicas (test and set, cmp and swap) Qu pasa en multiprocesadores?

Implementacin desabilitando interrupciones

Idea is desabilitar las interrupciones en acquire() y habiliarlas en release() Quin podra hacer esto? Es esto suficiente en un sistema con mltiples procesadores?

No. por qu?

Manejadas en el kernel, pueden servir de base para otras primitivas

Spinlocks: using test and set

Arquitectura de la CPU proporciona instruccin Lock_t L = false; atmica


bool test_and_set(bool &target) { bool old = target; target = true; return old; } void acquire(lock){ while(test_and_set(L)); } void release(L){ L = false; } 1 1

target = 0

target = 1 Retorna old = 0

target = 1

target = 1 Retorna old = 1

Anlisis: Recordando requerimientos secciones crticas


Exclusion mutua? Progreso? Espera finita? Eficiencia?

Problemas con spinlocks

Si hebra est en loop esperando por adquirir lock, la hebra que tiene lock no puede progresar

O bien se puede perder mucho tiempo de CPU haciendo algo til

hebras que estn esperando en spinlock, incluso hebra que tiene lock

Por qu? Contencin en protocolo de coherencia de memoria Cuando hebra tiene xito invalidacin de caches locales

Se usan de base para otros mecanismos de sincronizacin

Cuando tiempo de espera para conseguir lock es corto se pueden usar spinlocks (eficientes) y no hay demasiadas hebras esperando por lock

Desempeo

Suponga que costo de bloqueo es N ciclos

Bloquear y resumir hebra

Si hebra obtiene lock despus de M ciclos de espera ocupada (spinning) (M <= N) entonces M es el costo ptimo

Alternativa de bloqueo inmediato habra sido el costo N, con spinning conseguimos M Si hebra espera por N ciclos spinning y luego se bloquea y resume porque lock fue liberado Costo bloqueo en 2N ( N para spinning y N para bloqueo y resumen de hebra) Desempeo siempre un factor de de 2 del ptimo

Peor caso

Ejemplo mutex pthreads

Escriba un programa multihebra que cree 2000 hebras, 1000 incrementan una variable global y 1000 que la decrementan e imprima valor final

Por cada hebra sumadora cree una restadora en el cdigo

Entregar valor inicial de la variable en argumento Leer el valor final desde la hebra principal (la que crea las hebras sumadoras y las restadoras) Compile (acurdese de -pthread en lnea de compilacin) y ejecute. Observe si ve diferencia en el valor de retorno del valor final en la variable global Agregue mutexes para solucionar sus problemas Mida tiempos de ejecucin con y sin sincronizacin

Semforos

Primitiva de sincronizacin ms elaborada que mutex (locks) Inventados por Dijkstra (en SO THE implementado por niveles) Objeto atmico con valor y cola de espera Operaciones P(sem) y V(sem)

P(sem)/Wait(sem)/Down(sem):

Sem.valor-If (sem.valor < 0) bloquea hebra (agrega a cola de espera) Else hebra puede entrar a Seccin crtica Sem.valor++; If (Existe hebra en cola de espera) despierta a una

V(sem)/Signal(sem)/Up(sem)

Valor de semforo puede ser > 1, como contador atmico

(= 1 es como lock)

Implementacin de semforos
typedef struct { int valor; struct hebra *L; } semaforo; void wait(semaforo S) { S.valor--; if (S.valor < 0){ agregar hebra a S.L; block(); } } void signal(semaforo S){ S.valor++; if (S.valor <= 0){ remover hebra T de S.L; wakeup(T); } }

Tipos de semforos

Binarios (mutex)

Garantizan exclusin mutua Contador (valor) de semforo inicializado en 1 Representan recursos con mas de una unidad disponible Contador inicializado en N

Contadores

N cantidad de recursos disponibles

Ejemplos bsicos de sincronizacin

Productor/consumidor

1 cola circular compartida por hebras

Buffer en memoria con N slots disponibles

X hebras productoras generan informacin que agregan a cola Y hebras consumidoras extraen informacin de cola

Productor Agrega item usando puntero in out in

Consumidor Remueve item usando puntero out

Algoritmo Productor/Consumidor
int contador = 0; //indica nmero de items en buffer Tipo buffer[N]; int in = 0; int out = 0;

Productor while (true) { /* produce un item en proxProd */ while (contador == N); //espera buffer[in] = proxProd; in = (in + 1) % N; contador++; }

Consumidor while (true) { while (contador == 0); //espera proxCons = buffer[out]; out = (out + 1) % N; contador--; /* consume prodCons */ }

Cmo resolver el problema?

Identificar restricciones inherentes al problema


Existe estado compartido? Donde se pueden producir problemas?

Condiciones de carrera?

Es posible resolver problemas

Cmo ?

Solucin con locks


int contador = 0; //indica nmero de items en buffer char buffer[N]; int in = 0; int out = 0; lock_t mutex; Consumidor Productor while (true) { /* produce un item en proxProd */ lock(mutex); while(contador == N){ unlock(mutex); yield(); lock(mutex); } buffer[in] = proxProd; in = (in + 1) % N; contador++; unlock(mutex); } While(true){ lock(mutex); while(contador == 0){ unlock(mutex); yield(); lock(mutex); } proxCons = buffer[out]; out = (out + 1) % N; contador--; unlock(mutex); /* consume proxCons */ }

Solucin usando semforos

Especificar condiciones de espera y sealizacin

Mutex? Contadores?

Identificar semforos necesarios


Proporcionar algoritmos

Solucin usando semforos


int contador = 0; //indica nmero de items en buffer char buffer[N]; int in = 0; int out = 0; sem mutex=1; sem vacio = N; sem lleno = 0; Productor while (true) { /* produce un item en proxProd */ wait(vacio); wait(mutex); buffer[in] = proxProd; in = (in + 1) % N; contador++; signal(mutex); signal(lleno); } Consumidor While(true){ wait(lleno); wait(mutex); proxCons = buffer[out]; out = (out + 1) % N; contador--; signal(mutex); signal(vacio); /* consume proxCons */ }

También podría gustarte