Publicado el 14 de Enero del 2017
790 visualizaciones desde el 14 de Enero del 2017
98,7 KB
22 paginas
Creado hace 11a (14/10/2013)
Master en Computación
Programación Concurrente
Bloque II: Programación concurrente en POSIX
Introducción al estándar POSIX
Tema 1.
Tema 2. Sistema Operativo MaRTE OS
Tema 3. Gestión de Threads
Tema 4. Gestión del Tiempo
Tema 5. Planificación de Threads
Tema 6. Sincronización
Tema 7. Señales
Tema 8. Temporizadores y Relojes de Tiempo de Ejecución
Programación Concurrente
Tema 6. Sincronización
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
1
6.1. Mecanismos de sincronización POSIX
6.2. Semáforos Contadores
6.3. Mutexes
6.4. Variables Condicionales
6.5.
Implementación de secciones críticas y mutexes en MaRTE
OS
© M. Aldea, M. González
oct-13
2
6.1 Mecanismos de sincronización POSIX
Programación Concurrente
Tema 6. Sincronización
6.1 Mecanismos de sincronización POSIX
Los procesos o threads pueden:
• ser independientes de los demás
• cooperar entre ellos
• competir por el uso de recursos compartidos
En los dos últimos casos los procesos deben sincronizarse para:
• intercambiar datos o eventos, mediante algún mecanismo de
intercambio de mensajes
• usar recursos compartidos (datos o dispositivos) de manera
mutuamente exclusiva
- para asegurar su congruencia ante accesos concurrentes
- el acceso al recurso puede ser condicional, de forma que sólo
se pueda acceder a él si se encuentra en el estado apropiado
Programación Concurrente
© M. Aldea, M. González
oct-13
3
Tema 6. Sincronización
6.1 Mecanismos de sincronización POSIX
Mecanismos de sincronización POSIX (cont.)
Mecanismos de sincronización proporcionados por el POSIX:
• Sincronización por intercambio de mensajes:
- señales
- semáforos contadores
- colas de mensajes (no vistas en este curso)
• Exclusión mutua:
- semáforos contadores
- mutexes
- variables condicionales
El POSIX no proporciona monitores ni regiones críticas
• aunque pueden construirse utilizando semáforos o mutexes y
variables condicionales
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
6.1 Mecanismos de sincronización POSIX
Variables atómicas compartidas
Un mecanismo primitivo de sincronización consiste en la
utilización de variables atómicas compartidas
• variable atómica: puede ser leída o escrita con una sola
instrucción del procesador
- su tamaño máximo está limitado por la anchura del bus (16/
32/64 bits)
• la congruencia ante accesos concurrentes está asegurada
Una variable compartida entre threads, manejadores de señal o
manejadores de interrupción debe ser marcada como “volátil”
• indica al compilador que no debe optimizar basándose en su
valor puesto que puede cambiar “inesperadamente”
• en C se utiliza la palabra reservada volatile:
volatile int flag;
4
5
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
6.2 Semáforos Contadores
6.2 Semáforos Contadores
Es un recurso compartible con un valor entero no negativo
Cuando el valor es cero, el semáforo no está disponible
Se utiliza tanto para sincronización de acceso mutuamente
exclusivo, como de señalización y espera (paso de mensajes)
• tanto entre procesos como entre threads
Operaciones que se aplican al semáforo:
• esperar (wait): si el valor es 0, el proceso o thread se añade a
una cola; si el valor es mayor que 0, se decrementa
• señalizar (post): si hay procesos o threads esperando, se
elimina uno de la cola y se le activa; si no, se incrementa el valor
Existen semáforos con nombre, y sin nombre
Programación Concurrente
© M. Aldea, M. González
oct-13
6
Tema 6. Sincronización
6.2 Semáforos Contadores
Inicializar/destruir un semáforo sin nombre
• Inicializar/destruir un semáforo sin nombre:
#include <semaphore.h>
int sem_init (sem_t *sem,
int pshared,
unsigned int value);
• inicializa el semáforo al que apunta sem
• si pshared es 0 el semáforo sólo puede ser usado por threads
del mismo proceso
• si pshared no es 0, el semáforo se puede compartir entre
diferentes procesos
• value es el valor inicial del semáforo
• Destruir un semáforo sin nombre:
int sem_destroy (sem_t *sem);
© M. Aldea, M. González
oct-13
7
Programación Concurrente
Tema 6. Sincronización
6.2 Semáforos Contadores
Abrir/cerrar un semáforo con nombre
• Abrir (e inicializar) un semáforo con nombre:
sem_t *sem_open(const char *name, int oflag,
[,mode_t mode, unsigned int value]);
• devuelve un puntero al semáforo
• name debe tener el formato "/nombre"
• oflag indica las opciones:
- O_CREAT: si el semáforo no existe, se crea; en este caso se
requieren los parámetros mode, que indica permisos, y
value, que es el valor inicial
- O_EXCL: si el semáforo ya existe, error
• Cerrar y borrar un semáforo con nombre:
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
Programación Concurrente
Tema 6. Sincronización
Esperar en un semáforo
© M. Aldea, M. González
oct-13
6.2 Semáforos Contadores
• Espera incondicional
int sem_wait(sem_t *sem);
• si valor>0 entonces valor:=valor-1
• si valor=0 el thread se bloquea y encola en la cola del
semáforo
• Operación no bloqueante
int sem_trywait(sem_t *sem);
• si valor>0 entonces valor:=valor-1
• si valor=0 retorna -1 inmediatamente y errno vale EAGAIN
Programación Concurrente
© M. Aldea, M. González
oct-13
8
9
Tema 6. Sincronización
6.2 Semáforos Contadores
(cont.)
Esperar en un semáforo
• Espera con tiempo límite
int sem_timedwait(sem_t *sem,
const struct timespec *abs_timeout);
• si valor>0 entonces valor:=valor-1
• si valor=0 el thread se bloquea y encola en la cola del
semáforo
• si se alcanza el tiempo límite la función retorna -1 y errno vale
ETIMEDOUT
• el tiempo límite está basado en el reloj del sistema o en el
CLOCK_REALTIME (en el caso de que el S.O. lo soporte)
Programación Concurrente
Tema 6. Sincronización
Señalizar un semáforo
• Señalizar un semáforo:
© M. Aldea, M. González
oct-13
10
6.2 Semáforos Contadores
int sem_post(sem_t *sem);
• si hay algún thread esperando en la cola: se activa el de mayor
prioridad
• si no, valor:=valor+1
• Leer el valor de un semáforo:
int sem_getvalue(sem_t *sem, int *sval);
• retorna en sval el valor que tenía el semáforo en el momento
de la llamada a la función
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
11
6.2 Semáforos Contadores
Uso de semáforos para exclusión mutua
void *t1 (void *a) {
...;
sem_wait(&sem);
usa el recurso
compartido;
sem_post(&sem);
...
}
void *t2 (void *a) {
...;
sem_wait(&sem);
usa el recurso
compartido;
sem_post(&sem);
...
}
// crea el sem con valor inicial 1
sem_init(&sem,0,1)
recurso
Programación Concurrente
© M. Aldea, M. González
oct-13
12
Tema 6. Sincronización
Uso de semáforos para señalización y espera
6.2 Semáforos Contadores
void *t1 (void *a) {
...;
sem_wait(&sem);
...
}
void *t2 (void *a) {
...;
sem_post(&sem);
...
evento
}
// crea el sem con valor inicial 0
sem_init(&sem,0,0)
© M. Aldea, M. González
oct-13
13
6.2 Semáforos Contadores
Programación Concurrente
Tema 6. Sincronización
Ejemplo: Señalización con semáforos
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <misc/error_checks.h>
sem_t sem;
// Thread que espera el semáforo
void * waiter(void *arg)
{
while (1) {
printf(" -Waiter antes de esperar en el semáforo \n");
CHKE( sem_wait(&sem) );
printf(" -Waiter después de esperar \n");
}
return NULL;
}
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
14
6.2 Semáforos Contadores
Ejemplo: Señalización con semáforos (cont.)
// Thread que señaliza el semáforo
void * signaler(void *arg)
{
printf ("Signaler antes de señalizar 3 veces \n");
CHKE( sem_post(&sem) );
CHKE( sem_post(&sem) );
CHKE( sem_post(&sem) );
sleep(10); // deja ejecutar al thread señalizado
while (1) {
printf ("Signaler antes de señalizar \n");
CHKE( sem_post(&sem) );
sleep(10); // deja ejecutar al thread señalizado
}
return NULL;
}
Programación Concurrente
© M. Aldea, M. González
oct-13
15
Tema 6. Sincronización
6.2 Semáforos Contadores
Ejemplo: Señalización con semáforos (cont.)
int main()
{
pthread_t t1,t2;
int ret;
CHKE( sem_init(&sem, 0, 1) );
// Crea los threads
CHK( pthread_create(&t1, NULL, waiter, NULL) );
CHK( pthread_create(&t2, NULL, signaler, NULL) );
// deja ejecutar un rato y termina
sleep(40);
exit(0);
}
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
6.3 Mutexes
Objeto de sincronización parecido a los semáforos
16
6.3 Mutexes
• por el que múltiples threads/procesos acceden de forma
mutuamente exclusiva a un recurso
• pero con un nuevo concepto: cada mutex tiene un propietario
Operaciones:
- tomar o bloquear (lock): si el mutex está libre, se toma y el
thread se convierte en propietario; si no se suspende y se
añade a una cola
- liberar (unlock): si hay threads esperando en la cola, el de
mayor prioridad toma el mutex y se convierte en su nuevo
propietario; si no, el mutex queda libre; sólo el propietario del
mutex puede invocar esta operación
Programación Concurrente
Tema 6. Sincronización
© M. Aldea, M. González
oct-13
Protocolos de sincronización
Patologías relacionadas con la sincronización:
17
6.3 Mutexes
• Interbloqueos
• Falta de vivacidad: Inversión de prioridad no acotada (ver
transparencia siguiente)
Los mutexes permiten los protocolos:
• Herencia de Prioridad
• Protección por Prioridad (o “Techo de Prioridad Inmediato”)
Ambos acotan la inversión de prioridad
• a la duración de una o varias secciones críticas
Protección por Prioridad evita los interbloqueos
• siempre que las tareas no se suspendan dentro de las regiones
críticas
Programación Concurrente
© M. Aldea, M. González
oct-13
18
Tema 6. Sincronización
Inversión de prioridad no acotada
Ocurre cuando no se us
+
Comentarios de: Master en Computación - Programación Concurrente - Bloque II: Programación concurrente en POSIX Introducción al estándar POSIX - Tema 6. Sincronización (0)
No hay comentarios