Cap.5. Comunicación y sincronización entre procesos

Anuncio
Sistemas operativos: una visión aplicada
Capítulo 5
Comunicación y sincronización
de procesos
Contenido
•
•
•
•
•
•
•
•
Procesos concurrentes.
Problemas clásicos de comunicación y sincronización.
Mecanismos de comunicación y sincronización.
Paso de mensajes.
Aspectos de implementación
Interbloqueos.
Servicios POSIX
Servicios Win32
Sistemas operativos: una visión aplicada
1
© J. Carretero, F. García, P. de Miguel, F. Pérez
1
Procesos concurrentes
• Modelos
– Multiprogramación en un único procesador
– Multiprocesador
– Multicomputador (proceso distribuido)
• Razones
– Compartir recursos físicos
– Compartir recursos lógicos
– Acelerar los cálculos
– Modularidad
– Comodidad
Sistemas operativos: una visión aplicada
2
© J. Carretero, F. García, P. de Miguel, F. Pérez
Sistema multiprogramado con un una CPU
Proceso A
Proceso B
Proceso C
Tiempo
Sistemas operativos: una visión aplicada
3
© J. Carretero, F. García, P. de Miguel, F. Pérez
2
Ejecución en un sistema multiprocesador
Proceso A
CPU 1
Proceso B
CPU 2
Proceso C
Proceso D
Tiempo
Sistemas operativos: una visión aplicada
4
© J. Carretero, F. García, P. de Miguel, F. Pérez
Tipos de procesos concurrentes
• Tipos de procesos
– Independientes
– Cooperantes
• Interacción entre procesos
– Compiten por recursos
– Comparten recursos
Sistemas operativos: una visión aplicada
5
© J. Carretero, F. García, P. de Miguel, F. Pérez
3
Problemas clásicos de comunicación y sincronización
•
•
•
•
El problema de la sección crítica
El problema del productor-consumidor
El problema de los lectores-escritores
Comunicación cliente-servidor
Sistemas operativos: una visión aplicada
6
© J. Carretero, F. García, P. de Miguel, F. Pérez
Problema de la sección crítica
• Sistema compuesto por n procesos
• Cada uno tiene un fragmento de código: sección crítica
• Sólo uno de los procesos en cada instante puede ejecutar en la
sección crítica
– Cuando un proceso está ejecutando en la sección crítica,
ningún otro puede hacerlo
Sistemas operativos: una visión aplicada
7
© J. Carretero, F. García, P. de Miguel, F. Pérez
4
Ejemplo 1
Proceso ligero
principal
ni =51
nf = 100
ni = 1
nf = 50
S2 = 51 +....+ 100
S1 = 1 +...+ 50
suma_total = S1 + S2
Sistemas operativos: una visión aplicada
8
© J. Carretero, F. García, P. de Miguel, F. Pérez
Ejemplo 1
• Calcula la suma de los N primeros números utilizando procesos
ligeros.
int suma_total = 0;
void suma_parcial(int ni, int nf) {
int j = 0;
int suma_parcial = 0;
for (j = ni; j <= nf; j++)
suma_parcial = suma_parcial + j;
suma_total = suma_total + suma_parcial;
pthread_exit(0);
}
• Si varios procesos ejecutan concurrentemente este código se
puede obtener un resultado incorrecto.
• Solución: secciones críticas
Sistemas operativos: una visión aplicada
9
© J. Carretero, F. García, P. de Miguel, F. Pérez
5
Ejemplo con sección crítica
void suma_parcial(int ni, int nf) {
int j = 0;
int suma_parcial = 0;
for (j = ni; j <= nf; j++)
suma_parcial = suma_parcial + j;
<Entrada en la sección crítica>
suma_total = suma_total + suma_parcial;
<Salida de la sección crítica>
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
10
© J. Carretero, F. García, P. de Miguel, F. Pérez
Ejemplo 2
void ingresar(char *cuenta, int cantidad) {
int saldo, fd;
fd = open(cuenta, O_RDWR);
read(fd, &saldo, sizeof(int));
saldo = saldo + cantidad;
lseek(fd, 0, SEEK_SET);
write(fd, &saldo, sizeof(int));
close(fd);
return;
}
• Si dos procesos ejecutan concurrentemente este código se puede
perder algún ingreso.
• Solución: secciones críticas
Sistemas operativos: una visión aplicada
11
© J. Carretero, F. García, P. de Miguel, F. Pérez
6
Ejemplo 2 con sección crítica
void ingresar(char *cuenta, int cantidad) {
int saldo, fd;
fd = open(cuenta, O_RDWR);
<Entrada en la sección crítica>
read(fd, &saldo, sizeof(int));
saldo = saldo + cantidad;
lseek(fd, 0, SEEK_SET);
write(fd, &saldo, sizeof(int));
<Salida de la sección crítica>
close(fd);
return;
}
Sistemas operativos: una visión aplicada
12
© J. Carretero, F. García, P. de Miguel, F. Pérez
Ejemplo 3
Procesador 2
Procesador 1
Lee PID
Registro o
posición de memoria
PID = 500
PID = 500
Lee PID
Incrementa y
asigna PID
PID = 501 Escribe PID
PID = 501
PID = 500
Incrementa y
asigna PID
PID = 501
PID = 501
Sistemas operativos: una visión aplicada
13
Escribe PID
© J. Carretero, F. García, P. de Miguel, F. Pérez
7
Solución al problema de la sección crítica
• Estructura general de cualquier mecanismo utilizado para
resolver el problema de la sección crítica:
Entrada en la sección crítica
Código de la sección crítica
Salida de la sección crítica
• Requisitos que debe ofrecer cualquier solución para resolver el
problema de la sección crítica:
– Exclusión mutua
– Progreso
– Espera limitada
Sistemas operativos: una visión aplicada
14
© J. Carretero, F. García, P. de Miguel, F. Pérez
Problema del productor-consumidor
Proceso
Consumidor
Proceso
Productor
Flujo de
datos
Mecanismo de
comunicación
Sistemas operativos: una visión aplicada
15
© J. Carretero, F. García, P. de Miguel, F. Pérez
8
El problema de los lectores-escritores
Lector
Lector
Escritor
Lector
Escritor
Recurso
Sistemas operativos: una visión aplicada
16
© J. Carretero, F. García, P. de Miguel, F. Pérez
Comunicación cliente-servidor
Computador
Computador
Petición
Proceso
cliente
Proceso
servidor
S.O.
Respuesta
Sistemas operativos: una visión aplicada
17
© J. Carretero, F. García, P. de Miguel, F. Pérez
9
Mecanismos de comunicación
•
•
•
•
Archivos
Tuberías (pipes, FIFOS)
Variables en memoria compartida
Paso de mensajes
Sistemas operativos: una visión aplicada
18
© J. Carretero, F. García, P. de Miguel, F. Pérez
Mecanismos de Sincronización
• Construcciones de los lenguajes concurrentes (procesos ligeros)
• Servicios del sistema operativo:
– Señales (asincronismo)
– Tuberías (pipes, FIFOS)
– Semáforos
– Mutex y variables condicionales
– Paso de mensajes
• Las operaciones de sincronización deben ser atómicas
Sistemas operativos: una visión aplicada
19
© J. Carretero, F. García, P. de Miguel, F. Pérez
10
Tuberías (POSIX)
• Mecanismo de comunicación y sincronización
– Sin nombre: pipes
– Con nombre: FIFOS
• Sólo puede utilizarse entre los procesos hijos del proceso que
creó el pipe
int pipe(int fildes[2]);
•
•
•
Identificación: dos descriptores de archivo
– Para lectura
– Para escritura
Flujo de datos: unidireccional
Mecanismo con capacidad de almacenamiento
Sistemas operativos: una visión aplicada
20
© J. Carretero, F. García, P. de Miguel, F. Pérez
Comunicación unidireccional con tuberías
write
Proceso
de Usuario
Proceso
de Usuario
read
SO
pipe
Flujo de datos
Sistemas operativos: una visión aplicada
21
© J. Carretero, F. García, P. de Miguel, F. Pérez
11
Comunicación bidireccional con tuberías
write
Proceso
de Usuario
write
read
Proceso
de Usuario
read
SO
pipe
Flujo de datos
pipe
Flujo de datos
Sistemas operativos: una visión aplicada
22
© J. Carretero, F. García, P. de Miguel, F. Pérez
Tuberías (II)
• read(fildes[0], buffer, n)
– Pipe vacío se bloquea el lector
– Pipe con p bytes
• Si p ≥ n devuelve n
• Si p < n devuelve p
– Si pipe vacío y no hay escritores devuelve 0
•
write(fildes[1], buffer, n)
– Pipe lleno se bloquea el escritor
– Si no hay lectores se recibe la señal SIGPIPE
•
Lecturas y escrituras atómicas (cuidado con tamaños grandes)
Sistemas operativos: una visión aplicada
23
© J. Carretero, F. García, P. de Miguel, F. Pérez
12
Secciones críticas con tuberías
void main(void) {
int fildes[2];
char c;
/* pipe para sincronizar */
/* caracter para sincronizar */
pipe(fildes);
write(fildes[1], &c, 1);
/* necesario para entrar en la
seccion critica la primera vez */
/* proceso hijo */
if (fork() == 0) {
for(;;) {
read(fildes[0], &c, 1); /* entrada seccion critica */
< Seccion critica >
write(fildes[1], &c, 1); /* salida seccion critica */
}
Sistemas operativos: una visión aplicada
24
© J. Carretero, F. García, P. de Miguel, F. Pérez
Secciones críticas con tuberías (II)
} else {
/* proceso padre */
for(;;) {
read(fildes[0], &c, 1);
/* entrada seccion critica */
< seccion critica >
write(fildes[1], &c, 1); /* salida seccion critica */
}
}
}
Sistemas operativos: una visión aplicada
25
© J. Carretero, F. García, P. de Miguel, F. Pérez
13
Productor-consumidor con tuberías
void main(void) {
int fildes[2]; /* pipe para comunicar y sincronizar */
int dato_p[4]; /* datos a producir */
int dato_c;
/* dato a consumir */
pipe(fildes);
if (fork() == 0) { /* proceso hijo: productor */
for(;;) {
< producir dato_p, escribe 4 enteros *
write(fildes[1], dato_p, 4*sizeof(int));
}
Sistemas operativos: una visión aplicada
26
© J. Carretero, F. García, P. de Miguel, F. Pérez
Productor-consumidor con tuberías (II)
} else
{
/* proceso padre: consumidor */
for(;;) {
read(fildes[0], &dato, sizeof(int));
/* consumir dato, lee un entero */
}
}
}
Proceso
hijo
Sistemas operativos: una visión aplicada
Pipe
27
Proceso
padre
© J. Carretero, F. García, P. de Miguel, F. Pérez
14
Ejecución de mandatos con tuberías
/* programa que ejecuta el mandato ``ls | wc'' */
void main(void)
{
int fd[2];
pid_t pid;
ls
pipe
wc
if (pipe(fd) < 0) {
perror(``pipe'');
exit(-1);
}
pid = fork();
switch(pid) {
case -1:
/* error */
perror(``fork'');
exit(-1);
Sistemas operativos: una visión aplicada
28
© J. Carretero, F. García, P. de Miguel, F. Pérez
Ejecución de mandatos con tuberías (II)
case 0:
/* proceso hijo ejecuta ``ls'' */
close(fd[0]); /* cierra el pipe de lectura */
close(STDOUT_FILENO); /* cierra la salida estandar */
dup(fd[1]);
close(fd[1]);
execlp(``ls'',``ls'',NULL);
perror(``execlp'');
exit(-1);
default: /* proceso padre ejecuta ``wc'' */
close(fd[1]); /* cierra el pipe de escritura */
close(STDIN_FILENO); /* cierra la entrada estandar */
dup(fd[0]);
close(fd[0]);
execlp(``wc'',``wc'',NULL);
perror(``execlp'');
}
}
Sistemas operativos: una visión aplicada
29
© J. Carretero, F. García, P. de Miguel, F. Pérez
15
Ejecución de mandatos con tuberías (III)
•Proceso
•Proceso
•STDIN
•STDOUT
•Proceso
•STDIN
•STDOUT
•fd[0]
•fd[1]
•fork()
•STDIN
•STDOUT
•fd[0]
•fd[1]
•pipe(fd)
•pipe
•Proceso hijo
•STDIN
•STDOUT
•fd[0]
•fd[1]
•pipe
•Proceso
•Proceso hijo
•STDIN
•STDIN
•pipe
•exec
•STDOUT
•STDOUT
•Proceso
•Proceso hijo
•STDIN
•STDIN
•pipe
•STDOUT
•STDOUT
•ls
•wc
Sistemas operativos: una visión aplicada
•redirección
30
© J. Carretero, F. García, P. de Miguel, F. Pérez
Tuberías con nombre en POSIX (FIFOS)
•
•
•
•
Igual que los pipes
Mecanismo de comunicación y sincronización con nombre
Misma máquina
Servicios
– int mkfifo(char *name, mode_t mode);
• Crea un FIFO con nombre name
– int open(char *name, int flag);
• Abre un FIFO (para lectura, escritura o ambas)
• Bloquea hasta que haya algún proceso en el otro extremo
• Lectura y escritura mediante read() y write()
– Igual semántica que los pipes
• Cierre de un FIFO mediante close()
• Borrado de un FIFO mediante unlink()
Sistemas operativos: una visión aplicada
31
© J. Carretero, F. García, P. de Miguel, F. Pérez
16
Semáforos
•
•
•
•
Mecanismo de sincronización
Misma máquina
Objeto con un valor entero
Dos operaciones atómicas
– wait
– signal
Sistemas operativos: una visión aplicada
32
© J. Carretero, F. García, P. de Miguel, F. Pérez
Operaciones sobre semáforos
wait(s)
{
s = s - 1;
if (s < 0) {
<Bloquear al proceso>
}
}
signal(s)
{
s = s + 1;
if (s <= 0)
<Desbloquear a un proceso bloqueado por la
operacion wait>
}
}
Sistemas operativos: una visión aplicada
33
© J. Carretero, F. García, P. de Miguel, F. Pérez
17
Secciones críticas con semáforos
wait(s); /* entrada en la seccion critica */
< seccion critica >
signal(s); /* salida de la seccion critica */
•
El semáforo debe tener valor inicial 1
Valor del
semáforo (s)
P0
P1
P2
1
0
-1
wait(s)
wait(s)
wait(s)
-2
desbloquea
-1
signal(s)
desbloquea
0
signal(s)
Ejecutando código de la sección crítica
Proceso bloqueado en el semáforo
1
Sistemas operativos: una visión aplicada
signal(s)
34
© J. Carretero, F. García, P. de Miguel, F. Pérez
Semáforos POSIX
• int sem_init(sem_t *sem, int shared, int val);
– Inicializa un semáforo sin nombre
• int sem_destroy(sem_t *sem);
– Destruye un semáforo sin nombre
• sem_t *sem_open(char *name, int flag, mode_t mode,
int val);
– Abre (crea) un semáforo con nombre.
• int sem_close(sem_t *sem);
– Cierra un semáforo con nombre.
• int sem_unlink(char *name);
– Borra un semáforo con nombre.
• int sem_wait(sem_t *sem);
– Realiza la operación wait sobre un semáforo.
• int sem_post(sem_t *sem);
– Realiza la operación signal sobre un semáforo.
Sistemas operativos: una visión aplicada
35
© J. Carretero, F. García, P. de Miguel, F. Pérez
18
Productor-consumidor con semáforos
(buffer acotado y circular)
Productor
Consumidor
Sistemas operativos: una visión aplicada
36
© J. Carretero, F. García, P. de Miguel, F. Pérez
Productor-consumidor con semáforos (II)
#define MAX_BUFFER
#define DATOS_A_PRODUCIR
sem_t elementos;
sem_t huecos;
int buffer[MAX_BUFFER];
void main(void)
{
pthread_t th1, th2;
1024
100000
/* tamanio del buffer */
/* datos a producir */
/* elementos en el buffer */
/* huecos en el buffer */
/* buffer comun */
/* identificadores de threads */
/* inicializar los semaforos */
sem_init(&elementos, 0, 0);
sem_init(&huecos, 0, MAX_BUFFER);
Sistemas operativos: una visión aplicada
37
© J. Carretero, F. García, P. de Miguel, F. Pérez
19
Productor-consumidor con semáforos (III)
/* crear los procesos ligeros */
pthread_create(&th1, NULL, Productor, NULL);
pthread_create(&th2, NULL, Consumidor, NULL);
/* esperar su finalizacion */
pthread_join(th1, NULL);
pthread_join(th2, NULL);
sem_destroy(&huecos);
sem_destroy(&elementos);
exit(0);
}
Sistemas operativos: una visión aplicada
38
© J. Carretero, F. García, P. de Miguel, F. Pérez
Productor-consumidor con semáforos (IV)
void Productor(void)
/* codigo del productor */
{
int pos = 0; /* posicion dentro del buffer */
int dato;
/* dato a producir */
int i;
for(i=0; i < DATOS_A_PRODUCIR; i++ )
{
dato = i;
/* producir dato */
sem_wait(&huecos); /* un hueco menos */
buffer[pos] = i;
pos = (pos + 1) % MAX_BUFFER;
sem_post(&elementos); /* un elemento mas */
}
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
39
© J. Carretero, F. García, P. de Miguel, F. Pérez
20
Productor-consumidor con semáforos (V)
void Consumidor(void)
{
int pos = 0;
int dato;
int i;
/* codigo del Consumidor */
for(i=0; i < DATOS_A_PRODUCIR; i++ ) {
sem_wait(&elementos);
/* un elemento menos */
dato = buffer[pos];
pos = (pos + 1) % MAX_BUFFER;
sem_post(&huecos);
/* un hueco mas */
/* consumir dato */
}
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
40
© J. Carretero, F. García, P. de Miguel, F. Pérez
Lectores-escritores con semáforos
int dato = 5;
/* recurso */
int n_lectores = 0; /* numero de lectores */
sem_t sem_lec;
/* controlar el acceso n_lectores */
sem_t mutex;
/* controlar el acceso a dato */
void main(void)
{
pthread_t th1, th2, th3, th4;
sem_init(&mutex, 0, 1);
sem_init(&sem_lec, 0, 1);
pthread_create(&th1,
pthread_create(&th2,
pthread_create(&th3,
pthread_create(&th4,
Sistemas operativos: una visión aplicada
NULL,
NULL,
NULL,
NULL,
Lector, NULL);
Escritor, NULL);
Lector, NULL);
Escritor, NULL);
41
© J. Carretero, F. García, P. de Miguel, F. Pérez
21
Lectores-escritores con semáforos (II)
pthread_join(th1,
pthread_join(th2,
pthread_join(th3,
pthread_join(th4,
NULL);
NULL);
NULL);
NULL);
/* cerrar todos los semaforos */
sem_destroy(&mutex);
sem_destroy(&sem_lec);
exit(0);
}
Sistemas operativos: una visión aplicada
42
© J. Carretero, F. García, P. de Miguel, F. Pérez
Lectores-escritores con semáforos (III)
/* codigo del lector */
void Lector(void) { /* codigo del lector */
sem_wait(&sem_lec);
n_lectores = n_lectores + 1;
if (n_lectores == 1)
sem_wait(&mutex);
sem_post(&sem_lec);
printf(``%d\n'', dato);
/* leer dato */
sem_wait(&sem_lec);
n_lectores = n_lectores - 1;
if (n_lectores == 0)
sem_post(&mutex);
sem_post(&sem_lec);
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
43
© J. Carretero, F. García, P. de Miguel, F. Pérez
22
Lectores-escritores con semáforos (IV)
/* código del escritor */
void Escritor(void) {
sem_wait(&mutex);
dato = dato + 2;
sem_post(&mutex);
/* codigo del escritor */
/* modificar el recurso */
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
44
© J. Carretero, F. García, P. de Miguel, F. Pérez
Memoria compartida
Proceso A
Proceso B
Texto
Texto
Datos
var2
Datos
var1
2
Pila
Segmento
de memoria
compartida
Pila
• Declaración independiente de variables
Sistemas operativos: una visión aplicada
45
© J. Carretero, F. García, P. de Miguel, F. Pérez
23
Mutex
• Un mutex es un mecanismo de sincronización indicado para
procesos ligeros.
• Es un semáforo binario con dos operaciones atómicas:
– lock(m) Intenta bloquear el mutex, si el mutex ya está
bloqueado el proceso se suspende.
– unlock(m) Desbloquea el mutex, si existen procesos
bloqueados en el mutex se desbloquea a uno.
Sistemas operativos: una visión aplicada
46
© J. Carretero, F. García, P. de Miguel, F. Pérez
Secciones críticas con mutex
lock(m);
/* entrada en la seccion critica */
< seccion critica >
unlock(s); /* salida de la seccion critica */
•
La operación unlock debe realizarla el proceso ligero que
ejecutó lock
Proceso
ligero A
Proceso
ligero B
lock mutex
lock mutex
Sección
crítica
obtiene mutex
unlock mutex
Proceso ligero ejecutando
Proceso ligero bloqueado
Punto de sincronización
Sistemas operativos: una visión aplicada
47
© J. Carretero, F. García, P. de Miguel, F. Pérez
24
Paso de mensajes
• Permite resolver:
– Exclusión mutua
– Sincronizar entre un proceso que recibe un mensaje y otro que lo envía
– Comunicación de datos entre espacios de memoria diferentes (mismo
computador, diferentes computadores)
• Primitivas básicas:
– send(destino, mensaje) envía un mensaje al proceso destino
– receive(destino, mensaje) recibe un mensaje del proceso destino
• Múltiples soluciones
• Aspectos de diseño
– Tamaño del mensaje
– Flujo de datos (unidireccional, bidireccional)
– Nombrado
• Directo
• Indirecto (puertos, colas)
– Sincronización (síncrono, asíncrono)
– Almacenamiento
Sistemas operativos: una visión aplicada
48
© J. Carretero, F. García, P. de Miguel, F. Pérez
Uso de colas y puertos
Proceso cliente
Proceso cliente
send
Proceso cliente
Proceso cliente
receive
send
Puerto
mensaje
mensaje
Cola de mensajes
Comunicación con
colas de mensajes
Sistemas operativos: una visión aplicada
Comunicación con puertos
49
© J. Carretero, F. García, P. de Miguel, F. Pérez
25
Colas de mensajes POSIX
mqd_t mq_open(char *name, int flag, mode_t mode,
mq_attr *attr);
– Crea una cola de mensajes con nombre y atributos attr:
• Número máximo de mensajes.
• Tamaño máximo del mensaje.
• Bloqueante, No bloqueante.
int mq_close (mqd_t mqdes);
– Cierra una cola de mensajes.
int mq_unlink(char *name);
– Borra una cola de mensajes.
Sistemas operativos: una visión aplicada
50
© J. Carretero, F. García, P. de Miguel, F. Pérez
Colas de mensajes POSIX (II)
int mq_send(mqd_t mqdes, char *msg, size_t len,
int prio);
– Envía el mensaje msg de longitud len a la cola de mensajes
mqdes con prioridad prio;
– Si la cola está llena el envío puede ser bloqueante o no.
int mq_receive(mqd_t mqdes, char *msg, size_t len,
int prio);
– Recibe un mensaje msg de longitud len de la cola de
mensajes mqdes con prioridad prio;
– Recepción bloqueante o no.
Sistemas operativos: una visión aplicada
51
© J. Carretero, F. García, P. de Miguel, F. Pérez
26
Servidor multithread con colas de
mensajes
Proceso cliente
Proceso cliente
Cola del
cliente
Cola del
cliente
petición
petición
Proceso servidor
respuesta
Cola del
servidor
respuesta
Creación del
thread
Creación del
thread
Thread que
sirve la petición
Sistemas operativos: una visión aplicada
Thread que
sirve la petición
52
© J. Carretero, F. García, P. de Miguel, F. Pérez
Servidor multithread con colas de
mensajes (II)
/* estructura de un mensaje */
struct mensaje {
char buffer[1024]; /* datos a enviar */
char cliente[256]; /* cola del cliente */
};
/* mutex y variables condicionales para proteger la copia del
mensaje */
pthread_mutex_t mutex_mensaje;
int mensaje_no_copiado = TRUE;
pthread_cond_t cond;
void main(void){
mqd_t q_servidor;
struct mensaje mess;
struct mq_attr q_attr;
pthread_attr_t t_attr;
Sistemas operativos: una visión aplicada
/*
/*
/*
/*
cola del servidor */
mensaje a recibir */
atributos de la cola */
atributos de los threads */
53
© J. Carretero, F. García, P. de Miguel, F. Pérez
27
Servidor multithread con colas de
mensajes (II)
attr.mq_maxmsg = 20;
attr.mq_msgsize = sizeof(struct mensaje));
q_servidor = mq_open("SERVIDOR", O_CREAT|O_RDONLY, 0700, &attr);
pthread_mutex_init(&mutex_mensaje, NULL);
pthread_cond_init(&cond, NULL);
pthread_attr_init(&attr);
pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
Sistemas operativos: una visión aplicada
54
© J. Carretero, F. García, P. de Miguel, F. Pérez
Servidor multithread con colas de
mensajes (III)
while (TRUE) {
mq_receive(q_servidor, &mess, sizeof(struct mensaje), 0);
pthread_create(&thid, &attr, tratar_mensaje, &mess);
/* se espera a que el thread copie el mensaje */
pthread_mutex_lock(&mutex_mensaje);
while (mensaje_no_copiado)
pthread_cond_wait(&cond, &mutex_mensaje);
mensaje_no_copiado = TRUE;
pthread_mutex_unlock(&mutex_mensaje);
}
}
Sistemas operativos: una visión aplicada
55
© J. Carretero, F. García, P. de Miguel, F. Pérez
28
Servidor multithread con colas de
mensajes (IV)
void tratar_mensaje(struct mensaje *mes)
{
struct mensaje mensaje_local;
struct mqd_t q_cliente;
/* cola del cliente */
struct mensaje respueta; /* mensaje de respuesta al cliente */
/* el thread copia el mensaje */
pthread_mutex_lock(&mutex_mensaje);
memcpy((char *) &mensaje_local, (char *)&mes,
sizeof(struct mensaje));
/* ya se puede despertar al servidor*/
pthread_mutex_lock(&mutex_mensaje);
mensaje_no_copiado = FALSE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex_mensaje);
Sistemas operativos: una visión aplicada
56
© J. Carretero, F. García, P. de Miguel, F. Pérez
Servidor multithread con colas de
mensajes (V)
/* ejecutar la petición del cliente */
/* y preparar respuesta */
/* responder al cliente a su cola */
q_cliente = mq_open(mensaje_local.nombre, O_WRONLY);
mqsend(q_cliente, (char *) &respueta, sizeof(respuesta), 0);
mq_clise(q_cliente);
pthread_exit(0);
}
Sistemas operativos: una visión aplicada
57
© J. Carretero, F. García, P. de Miguel, F. Pérez
29
Ejemplo de código cliente
/* estructura de un mensaje */
struct mensaje {
char buffer[1024]; /* datos a enviar */
char cliente[256]; /* cola del cliente */
};
void main(void)
{
mqd_t q_servidor;
mqd_t q_cliente;
struct mq_attr q_attr;
struct mensaje peticion;
struct mensaje respuesta;
/*
/*
/*
/*
/*
cola del servidor */
cola del cliente */
atributos de la cola */
peticion al servidor */
respuesta del servidor */
attr.mq_maxmsg = 1;
attr.mq_msgsize = sizeof(struct mensaje));
Sistemas operativos: una visión aplicada
58
© J. Carretero, F. García, P. de Miguel, F. Pérez
Ejemplo de código cliente (II)
q_cliente = mq_open("CLIENTE", O_CREAT|O_RDONLY, 0700, 0);
q_servidor = mq_open("SERVIDOR", O_WRONLY);
/* preparar peticion */
mq_send(q_servidor, &petcicion, sizeof(struct mensaje), 0);
/* esperar respuesta */
mq_receive(q_cliente, &respuesta, sizeof(struct mensaje), 0);
mq_close(q_servidor);
mq_close(q_cliente);
mq_unlink("CLIENTE");
exit(0);
}
Sistemas operativos: una visión aplicada
59
© J. Carretero, F. García, P. de Miguel, F. Pérez
30
Implementación de mecanismos de sincronización
•
Espera activa:
wait(s) {
s = s – 1;
while (s < 0)
;
signal(s) {
s = s + 1;
•
Espera pasiva
wait(s) {
s = s – 1;
if (s < 0)
Bloquear al proceso;
signal(s) {
s = s + 1;
if (s <= 0)
Desbloquear a un proceso bloqueado en la operación wait;
}
Sistemas operativos: una visión aplicada
60
© J. Carretero, F. García, P. de Miguel, F. Pérez
Implementación de la espera pasiva
• Operaciones para bloquear a un proceso en un semáforo
Tabla de procesos
BCP1 BCP2 BCP3 BCP4 BCP5 BCP6 BCP7 BCP8 BCP9 BCP10 BCP11 BCP12
Estado
PID
Bloq.
7
0
Cola asociada
al semáforo
6
1
Ejec.
11
5
0
8
9
7
(a)
Tabla de procesos
BCP1 BCP2 BCP3 BCP4 BCP5 BCP6 BCP7 BCP8 BCP9 BCP10 BCP11 BCP12
Estado
PID
Cola asociada
al semáforo
0
Bloq.
7
7
6
1
Bloq.
11
Bloq.
5
0
8
9
11
(b)
Sistemas operativos: una visión aplicada
61
© J. Carretero, F. García, P. de Miguel, F. Pérez
31
Implementación de la espera pasiva
•
Operaciones para desbloquear a un proceso bloqueado en un semáforo
Tabla de procesos
BCP1 BCP2 BCP3 BCP4 BCP5 BCP6 BCP7 BCP8 BCP9 BCP10 BCP11 BCP12
Estado
PID
0
Cola asociada
al semáforo
Bloq.
7
7
6
Bloq.
11
1
Bloq.
5
0
8
9
11
(a)
Tabla de procesos
BCP1 BCP2 BCP3 BCP4 BCP5 BCP6 BCP7 BCP8 BCP9 BCP10 BCP11 BCP12
Estado
PID
Cola asociada
al semáforo
0
Listo
7
6
Bloq.
11
1
Bloq.
5
0
8
9
11
(b)
Sistemas operativos: una visión aplicada
62
© J. Carretero, F. García, P. de Miguel, F. Pérez
Instrucciones hardware especiales
• Operación atómicas
int test-and-set(int *valor) {
int temp;
temp = *valor;
*valor = 1;
return temp;
/* true */
}
void swap (int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
return;
}
Sistemas operativos: una visión aplicada
63
© J. Carretero, F. García, P. de Miguel, F. Pérez
32
Sección crítica con test-and-set
• Los procesos comparten la variable lock (con valor inicial a
false)
while (test-and-set(&lock))
;
<Código de la sección crítica>
lock = false;
Sistemas operativos: una visión aplicada
64
© J. Carretero, F. García, P. de Miguel, F. Pérez
Sección crítica con swap
• Los procesos comparten la variable lock con valor inicial false.
• Cada proceso utiliza una variable local llave.
llave = true;
do
swap(lock, llave);
while (llave != false);
<Código de la sección crítica>
lock = false;
Sistemas operativos: una visión aplicada
65
© J. Carretero, F. García, P. de Miguel, F. Pérez
33
Implementación de un semáforo con test-and-set
signal(s){
while (test-and-set(&valor_s))
;
s = s + 1;
if ( s <= 0){
Desbloquear a un proceso
bloqueado en la operación
wait;
}
valor_s = false;
}
wait(s){
while (test-and-set(&valor_s))
;
s = s - 1;
if (s < 0){
valor_s = false;
Bloquear al proceso;
}
else
valor_s = false;
}
Sistemas operativos: una visión aplicada
66
© J. Carretero, F. García, P. de Miguel, F. Pérez
Interbloqueos
• Bloqueo permanente de un conjunto de procesos que compiten
por los recursos del sistema o se comunican entre sí.
•
Ejemplo: Si P y Q con semáforos con valor inicial 1
P1
wait(P)
wait(Q)
...
signal(P)
signal(Q)
Sistemas operativos: una visión aplicada
P2
wait(Q)
wait(P)
...
signal(Q)
siangl(P)
67
© J. Carretero, F. García, P. de Miguel, F. Pérez
34
Ejemplo de interbloqueo
P
A
B
Q
Sistemas operativos: una visión aplicada
68
© J. Carretero, F. García, P. de Miguel, F. Pérez
Interbloqueos II
•
Ejemplo: Si C1 y C2 son dos colas de mensajes:
P1
receive(P2, M)
...
send(P2, M)
•
P2
receive(P1, N)
...
send(P1, N)
Condiciones del interbloqueo:
– Exclusión mutua
– Retención y espera
– No apropiación
– Espera circular
Sistemas operativos: una visión aplicada
69
© J. Carretero, F. García, P. de Miguel, F. Pérez
35
Servicios Posix: Tuberías
• Crear una tubería sin nombre
– int pipe(int fildes[2]);
• Crear una tuberías con nombre
– int mkfifo(char *name, mode_t mode);
• Abrir una tubería con nombre
– int open(char *fifo, int flag);
• Cerrar una tubería
– int close(int fd);
• Borrar una tubería con nombre
– int unlink(char *fifo);
• Leer de una tubería
– int read(fildes[0], buffer, n);
• Escribir en una tubería
– int write(fildes[1], buffer, n);
Sistemas operativos: una visión aplicada
70
© J. Carretero, F. García, P. de Miguel, F. Pérez
Servicios Posix: Semáforos
• int sem_init(sem_t *sem, int shared, int val);
– Inicializa un semáforo sin nombre
• int sem_destroy(sem_t *sem);
– Destruye un semáforo sin nombre
• sem_t *sem_open(char *name, int flag, mode_t mode,
int val);
– Abre (crea) un semáforo con nombre.
• int sem_close(sem_t *sem);
– Cierra un semáforo con nombre.
• int sem_unlink(char *name);
– Borra un semáforo con nombre.
• int sem_wait(sem_t *sem);
– Realiza la operación wait sobre un semáforo.
• int sem_post(sem_t *sem);
– Realiza la operación signal sobre un semáforo.
Sistemas operativos: una visión aplicada
71
© J. Carretero, F. García, P. de Miguel, F. Pérez
36
Servicios Posix: Mutex
• int pthread_mutex_init(pthread_mutex_t *mutex,
pthread_mutexattr_t * attr);
– Inicializa un mutex.
• int pthread_mutex_destroy(pthread_mutex_t *mutex)
– Destruye un mutex.
• int pthread_mutex_lock(pthread_mutex_t *mutex);
– Intenta obtener el mutex. Bloquea al proceso ligero si el mutex se
encuentra adquirido por otro proceso ligero.
• int pthread_mutex_unlock(pthread_mutex_t *mutex);
– Desbloquea el mutex.
Sistemas operativos: una visión aplicada
72
;
© J. Carretero, F. García, P. de Miguel, F. Pérez
Servicios Posix: Colas de mensajes
• mqd_t mq_open(char *name, int flag, mode_t mode,
mq_attr *attr);
– Crea una cola de mensajes con nombre y atributos attr:
• Número máximo de mensajes.
• Tamaño máximo del mensaje.
• Bloqueante, No bloqueante.
• int mq_close (mqd_t mqdes);
– Cierra una cola de mensajes.
• int mq_unlink(char *name);
– Borra una cola de mensajes.
Sistemas operativos: una visión aplicada
73
© J. Carretero, F. García, P. de Miguel, F. Pérez
37
Servicios Posix: Colas de mensajes (II)
• int mq_send(mqd_t mqdes, char *msg, size_t len,
int prio);
– Envía el mensaje msg de longitud len a la cola de mensajes
mqdes con prioridad prio;
– Si la cola está llena el envío puede ser bloqueante o no.
• int mq_receive(mqd_t mqdes, char *msg, size_t len,
int prio);
– Recibe un mensaje msg de longitud len de la cola de
mensajes mqdes con prioridad prio;
– Recepción bloqueante o no.
Sistemas operativos: una visión aplicada
74
© J. Carretero, F. García, P. de Miguel, F. Pérez
Wind32: Servicios de sincronización
• DWORD WaitForSingleObject(HANDLE hHandle, DWORD
dwMilliseconds);
• DWORD WaitForMultipleObjects(DWORD nCount, CONST HANDLE
*lpHandles, BOOL fWaitFail, DWORD dwMilliseconds);
Sistemas operativos: una visión aplicada
75
© J. Carretero, F. García, P. de Miguel, F. Pérez
38
Wind32: Tuberías
• Crear una tubería sin nombre
– BOOL CreatePipe(PHANDLE phRead, PHANDLE phWrite,
LPSECURITY_ATTRIBUTES lpsa, DWORD cbPipe);
• Crear una tubería con nombre
– HANDLE CreateNamedPipe (LPCTSTR lpszPipeName, DWORD
fdwOpenMode, DWORD fdwPipeMode, DWORD nMaxInstances,
DWORD cbOutBuf, DWORD cbInBuf, DWORD dwTimeOut,
LPSECURITY_ATTRIBUTES lpsa);
• Abrir una tubería con nombre
– HANDLE
CreateFile(LPCSTR lpFileName, DWORD
dwDesiredAccess,DWORD dwShareMode, LPVOID
lpSecurityAttributes, DWORD CreationDisposition, DWORD
dwFlagsAndAttributes, HANDLE hTemplateFile);
Sistemas operativos: una visión aplicada
76
© J. Carretero, F. García, P. de Miguel, F. Pérez
Wind32: Tuberías (II)
• Cerrar una tubería con nombre
– BOOL CloseHandle (HANDLE hfile);
• Leer de una tubería
– BOOL ReadFile (HANDLE hFile, LPVOID lpBuffer, DWORD
nBytes,
LPDWORD lpnBytes, LPOVERLAPPED lpOverlapped);
• Escribir en una tubería
– BOOL WriteFile (HANDLE hFile, LPVOID lpBuffer, DWORD
nBytes,
LPDWORD lpnBytes, LPOVERLAPPED lpOverlapped);
Sistemas operativos: una visión aplicada
77
© J. Carretero, F. García, P. de Miguel, F. Pérez
39
Wind32: Secciones críticas
• VOID InitializeCriticalSection(
LPCCRITICAL_SECTION lpcsCriticalSection);
• VOID DeleteCriticalSection(
LPCCRITICAL_SECTION lpcsCriticalSection);
• VOID EnterCriticalSection(
LPCCRITICAL_SECTION lpcsCriticalSection);
• VOID LeaveCriticalSection(
LPCCRITICAL_SECTION lpcsCriticalSection);
Sistemas operativos: una visión aplicada
78
© J. Carretero, F. García, P. de Miguel, F. Pérez
Wind32: Semáforos
• Crear un semáforo
– HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpsa,
LONG cSemInitial, LONG cSemMax, LPCTSTR
lpszSemName);
• Abrir un semáforo
– HANDLE OpenSemaphore(LONG dwDesiredAccess, LONG
BinheritHandle, lpszName SemName);
• Operación wait
– DWORD WaitForSingleObject(HANDLE hSem,
DWORD dwTimeOut);
• Operación signal
– BOOL
ReleaseSemaphore(HANDLE
hSemaphore,
LONG cReleaseCount, LPLONG lpPreviousCount);
Sistemas operativos: una visión aplicada
79
© J. Carretero, F. García, P. de Miguel, F. Pérez
40
Wind32: Mutex y eventos
• Crear un mutex
– HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpsa,
BOOL fInitialOwner, LPCTSTR lpszMutexName);
• Abrir un mutex
– HANDLE OpenMutex(LONG dwDesiredAccess, LONG BineheritHandle,
lpszName SemName);
• Cerrar un mutex
– BOOL CloseHandle(HANDLE hObject);
• Operación lock
– DWORD WaitForSingleObject(HANDLE hMutex, DWORD dwTimeOut);
• Operación unlonk
– BOOL ReleaseMutex(HANDLE hMutex);
Sistemas operativos: una visión aplicada
80
© J. Carretero, F. García, P. de Miguel, F. Pérez
Wind32: Mutex y eventos (II)
• Crear un evento
– HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpsa, BOOL
fManualReset, BOOL fInitialState, LPTCSTR lpszEventName);
• Destruir un evento
– BOOL CloseHandle(HANDLE hObject);
• Esperar por un evento
– DWORD WaitForSingleObject(HANDLE hEvent, DWORD
dwTimeOut);
• Notificar un evento
– BOOL SetEvent(HANDLE hEvent);
– BOOL PulseEvent(HANDLE hEvent);
Sistemas operativos: una visión aplicada
81
© J. Carretero, F. García, P. de Miguel, F. Pérez
41
Descargar