Title: Comunicaci
1Comunicación y sincronización entre procesos
- María de los Santos Pérez Hernández
- mperez_at_fi.upm.es
2Índice
- Procesos concurrentes.
- El problema de la sección crítica.
- Problemas clásicos de comunicación y
sincronización. - Mecanismos de comunicación y sincronización.
- Interbloqueos.
3Referencias bibliográficas
- Sistemas Operativos una visión aplicada
- Jesús Carretero et al.
- McGraw Hill, 2001
- Sistemas Operativos Willian Stalling
- Willian Stalling
- Prentice Hall, 1997
- Operating System Concepts
- A. Silberschatz, P. Galvin
- Addison-Wesley, 1998
4Procesos concurrentes (I)
- 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
5Procesos concurrentes (II)
- Tipos de procesos
- Independientes
- Cooperantes
- Interacción entre procesos
- Compiten por recursos
- Comparten recursos
6Problema de la interacción entre procesos
(procesos ligeros)
- 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 lt 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
7Ejemplo con sección crítica(procesos ligeros)
- void suma_parcial(int ni, int nf)
-
- int j 0
- int suma_parcial 0
- for (j ni j lt 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)
- Requisitos para ofrecer secciones críticas
- Exclusión mutua
- Progreso
- Espera limitada
8Problema de la interacción entre procesos
- 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
9Ejemplo 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
- Requisitos para ofrecer secciones críticas
- Exclusión mutua
- Progreso
- Espera limitada
10Mecanismos de comunicación
- Ficheros
- Pipes
- FIFOS
- Variables en memoria compartida
- Paso de mensajes
- Sockets
11Mecanismos de Sincronización
- Construcciones de los lenguajes concurrentes
(procesos ligeros) - Servicios del sistema operativo
- Señales (asincronismo)
- Pipes
- FIFOS
- Semáforos
- Mutex y variables condicionales
- Paso de mensajes
- Las operaciones de sincronización deben ser
atómicas
12Características de los mecanismos de comunicación
- Identificación
- Mecanismos de nombrado
- Sin nombre
- Con nombre local
- Con nombre de red
- Identificador interno
- Identificador propio
- Descriptor de fichero
- Flujo de datos
- Unidireccional
- Bidireccional
- Buffering
- Sin buffering
- Con buffering
- Sincronización
- Síncrono (bloqueante)
- Asíncrono (no bloqueante)
13Problemas clásicos de comunicación y
sincronización
14Problemas clásicos de comunicación y
sincronización (II)
- Comunicación cliente-servidor
Computadora
Computadora
Petición
Proceso
Proceso
cliente
servidor
S.O.
Respuesta
15Pipes
- read(fildes0,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(fildes1, 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)
- Mecanismo de comunicación y sincronización sin
nombre - Sólo puede utilizarse entre los procesos hijos
del proceso que creó el pipe - int pipe(int fildes2)
- Identificación dos descriptores de fichero
- Flujo de datos unidireccional
- Con buffering
16Secciones críticas con pipes
- void main(void)
-
- int fildes2 / pipe sincronización /
- char c / carácter sincronización /
- pipe(fildes)
- write(fildes1, c, 1)
- / necesario para entrar en la seccion
- crítica la primera vez /
-
- if (fork() 0) / proceso hijo /
- for()
-
- read(fildes0, c, 1)
- / entrada sección crítica /
- / sección crítica /
- write(fildes1, c, 1)
- / salida seccion crítica /
-
- else / proceso padre /
-
- for()
-
- read(fildes0, c, 1) / entrada
sección crítica/ - / sección crítica /
- write(fildes1, c, 1) / salida
sección crítica / -
-
-
17Productor-consumidor con pipes
- void main(void)
-
- int fildes2 / pipe para comunicar y
sincronizar / - int dato_p4 / datos a producir /
- int dato_c / dato a consumir /
- pipe(fildes)
- if (fork() 0) / productor /
-
- for()
-
- / producir dato_p /
- write(fildes1, dato_p,
- 4sizeof(int))
-
-
-
- else / consumidor /
-
- for()
-
- read(fildes0, dato_c,
sizeof(int)) - / consumir dato /
-
-
-
18Ejecución de mandatos con pipes
- / programa que ejecuta el mandato ls wc /
- void main(void)
-
- int fd2
- pid_t pid
- if (pipe(fd) lt 0)
- perror(pipe'')
- exit(1)
-
- pid fork()
- switch(pid)
- case -1 / error /
- perror(fork'')
- exit(1)
- case 0 / proceso hijo ejecuta ls /
-
- close(fd0) / cierra el pipe de lectura /
- close(STDOUT_FILENO) / cierra la salida
estandar / - dup(fd1)
- close(fd1)
- execlp(ls'',ls'',NULL)
- perror(execlp'')
- exit(1)
- default / proceso padre ejecuta wc /
- close(fd1) / cierra el pipe de
escritura / - close(STDIN_FILENO) / cierra la entrada
estandar / - dup(fd0)
- close(fd0)
- execlp(wc'',wc'',NULL)
- perror(execlp'')
-
-
19Ejecución de mandatos con pipes (II)
20FIFOS
- Igual que los pipes
- Mecanismo de comunicación y sincronización con
nombre - Misma máquina
- Servicios
- mkfifo(char name,mode_t mode)
- Crea un FIFO con nombre name
-
- 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()
21Semáforos
- Mecanismo de sincronización
- Misma máquina
- Objeto con un valor entero
- Dos operaciones atómicas
- s_espera(s)
-
- s s - 1
- if (s lt 0)
- Bloquear al proceso
-
- s_abre(s)
-
- s s 1
- if (s lt 0)
- Desbloquear a un
- proceso bloqueado
-
- Secciones críticas con semáforos
- s_espera(s) / entrada en la seccion
critica / - / seccion critica /
- s_abre(s) / salida de la
- seccion critica /
- El semáforo debe tener valor inicial 1
22Semáforos POSIX
- 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 s_espera sobre un semáforo.
- int sem_post(sem_t sem)
- Realiza la operación s_abre sobre un semáforo.
23Productor-consumidor con semáforos (buffer
acotado y circular)
24Productor-consumidor con semáforos (II)
- / 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)
- sem_destroy(mutex)
- exit(0)
-
- define MAX_BUFFER 1024
- define DATOS_A_PRODUCIR 100000
- sem_t elementos / elementos buffer /
- sem_t huecos / huecos buffer /
- sem_t mutex / controla excl.mutua /
- int bufferMAX_BUFFER/buffer común/
- void main(void)
-
- pthread_t th1, th2 / id. threads/
- / inicializar los semaforos /
- sem_init(elementos, 0, 0)
- sem_init(huecos, 0, MAX_BUFFER)
- sem_init(mutex, 0, 1)
25Productor-consumidor con semáforos (III)
- void Productor(void) / código del productor /
-
- int pos 0 / posición dentro del buffer /
- int dato / dato a producir /
- int i
- for(i0 i lt DATOS_A_PRODUCIR i )
- dato i / producir dato /
- sem_wait(huecos) / un hueco menos /
- sem_wait(mutex) / entra en la sección
crítica / - bufferpos dato
- pos (pos 1) MAX_BUFFER
- sem_post(mutex) / deja la sección
crítica / - sem_post(elementos) / un elemento más
/ -
- pthread_exit(0)
26Productor-consumidor con semáforos (IV)
- void Consumidor(void) / código del Consumidor
/ -
- int pos 0
- int dato
- int i
- for(i0 i lt DATOS_A_PRODUCIR i )
- sem_wait(elementos) / un elemento
menos / - sem_wait(mutex) / entra en la sección
crítica / - dato bufferpos
- pos (pos 1) MAX_BUFFER
- sem_post(mutex) / deja la sección
crítica / - sem_post(huecos) / un hueco más /
- / consumir dato /
-
- pthread_exit(0)
27Lectores-escritores con semáforos
- int dato 5 / recurso /
- int n_lectores 0/ num. Lectores /
- sem_t sem_lec / acceso n_lectores /
- sem_t mutex / 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, NULL, Lector, NULL)
- pthread_create(th2, NULL, Escritor, NULL)
-
- pthread_create(th3, NULL, Lector, NULL)
- pthread_create(th4, NULL, Escritor, NULL)
-
- pthread_join(th1, NULL)
- pthread_join(th2, NULL)
- pthread_join(th3, NULL)
- pthread_join(th4, NULL)
- /cerrar todos los semaforos/
- sem_destroy(mutex)
- sem_destroy(sem_lec)
- exit(0)
-
28Lectores-escritores con semáforos (II)
- void Lector(void) / código 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)
29Lectores-escritores con semáforos (III)
- void Escritor(void) / código del escritor /
-
- sem_wait(mutex)
- dato dato 2 / modificar el recurso
/ - sem_post(mutex)
- pthread_exit(0)
-
30Objetos de memoria compartida
- Permiten crear un segmento de memoria compartido
entre procesos de la misma máquina. - Declaración independiente de variables
31Servicios
- int shm_open(char name, int oflag,
- mode_t mode)
- Crea un objeto de memoria a compartir entre
procesos - int shm_open (char name, int oflag)
- Sólo apertura
- int close(int fd)
- Cierre. El objeto persiste hasta que es cerrado
por el último proceso. - int shm_unlink(const char name)
- Borra una zona de memoria compartida.
- void mmap(void addr, size_t len, int prot,
- int flags, int fildes, off_t off)
- Establece una proyección entre el espacio de
direcciones de un proceso y un descriptor de
fichero u objeto de memoria compartida.
32Servicios (II)
- len especifica el número de bytes a proyectar.
- prot el tipo de acceso (lectura, escritura o
ejecución). - PROT_READ, PROT_WRITE, PROT_EXEC o PROT_NONE.
- flags especifica información sobre el manejo de
los datos proyectados (compartidos, privado,
etc.). - MAP_SHARED, MAP_PRIVATE, ...
- fildes representa el descriptor de fichero del
fichero o descriptor del objeto de memoria a
proyectar. - off desplazamiento dentro del fichero a partir de
cual se realiza la proyección. - void munmap(void addr, size_t len)
- Desproyecta parte del espacio de direcciones de
un proceso comenzando en la dirección addr. El
tamaño de la región a desproyectar es len.
33Productor-consumidor con objetos de memoria
compartida
- Productor
- Crea la zona de memoria compartida (shm_open)
- Le asigna espacio (ftruncate)
- int ftruncate (int fd, size_t len)
- Proyecta la zona de memoria compartida en su
espacio - de direcciones (mmap)
- Utiliza la zona de memoria compartida
- Desproyecta la zona de memoria compartida
- Cierra y borra el objeto de memoria compartida
34Productor-consumidor con objetos de memoria
compartida (II)
- Consumidor
- Debe esperar a que la zona de memoria compartida
este creada - Abre la zona de memoria compartida (shm_open)
- Proyecta la zona de memoria compartida en su
espacio de direcciones (mmap) - Utiliza la zona de memoria compartida
- Cierra el objeto de memoria compartida
35Código del productor
- define MAX_BUFFER 1024 / tamaño del
buffer / - define DATOS_A_PRODUCIR 100000 / datos a
producir / - sem_t elementos / elementos en el buffer /
- sem_t huecos / huecos en el buffer /
- sem_t mutex / acceso al buffer /
- void main(int argc, char argv)
-
- int shd
- int buffer / buffer común /
- / el productor crea el segmento de memoria
compartida / - shd shm_open("BUFFER", O_CREATO_WRONLY,
0700) - ftruncate(shd, MAX_BUFFER sizeof(int))
- / proyectar el objeto de memoria compartida en
el espacio - de direcciones del productor /
-
-
36Código del productor (II)
- buffer (int ) mmap(NULL, MAX_BUFFER
sizeof(int), - PROT_WRITE, MAP_SHARED,
shd, 0) - / El productor crea los semáforos /
- elementos sem_open("ELEMENTOS", O_CREAT,
0700, 0) - huecos sem_open("HUECOS", O_CREAT, 0700,
MAX_BUFFER) - mutex sem_open("MUTEX", O_CREAT, 0700, 1)
- Productor(buffer)
- / desproyectar el buffer compartido /
- munmap(buffer, MAX_BUFFER sizeof(int))
- close(shd) / cerrar el objeto de memoria
compartida / - shm_unlink("BUFFER") / borrar el objeto de
memoria / - sem_close(elementos) sem_close(huecos)
sem_close(mutex) - sem_unlink("ELEMENTOS") sem_unlink("HUECOS")
sem_unlink("MUTEX") -
37Código del productor (III)
- void Productor(int buffer) / código del
productor / - int pos 0 / posición dentro del buffer /
- int dato / dato a producir /
- int i
- for(i0 i lt DATOS_A_PRODUCIR i )
- dato i / producir dato /
- sem_wait(huecos) / un hueco menos /
- sem_wait(mutex)
- bufferpos dato
- pos (pos 1) MAX_BUFFER
- sem_post(mutex)
- sem_post(elementos) / un elemento más /
-
- return
38Código del consumidor
- define MAX_BUFFER 1024 / tamaño del
buffer / - define DATOS_A_PRODUCIR 100000 / datos a
producir / - sem_t elementos / elementos en el buffer /
- sem_t huecos / huecos en el buffer /
- sem_t mutex / acceso al buffer /
- void main(int argc, char argv)
-
- int shd
- int buffer / buffer común /
- / el consumidor abre el segmento de memoria
compartida / - shd shm_open("BUFFER", O_RDONLY)
- / proyectar el objeto de memoria compartida
en el espacio - de direcciones del productor /
-
39Código del consumidor (II)
- buffer (int ) mmap(NULL, MAX_BUFFER
sizeof(int), - PROT_READ, MAP_SHARED,
shd, 0) - / El consumidor abre los semáforos /
- elementos sem_open("ELEMENTOS", 0)
- huecos sem_open("HUECOS", 0)
- mutex sem_open("MUTEX", 0)
- Consumidor(buffer)
- / desproyectar el buffer compartido /
- munmap(buffer, MAX_BUFFER sizeof(int))
- close(shd) / cerrar el objeto de memoria
compartida / - / cerrar los semáforos /
- sem_close(elementos) sem_close(huecos)
sem_close(mutex) -
40Código del consumidor (III)
- void Consumidor(char buffer) /código del
Consumidor/ -
- int pos 0
- int i, dato
- for(i0 i lt DATOS_A_PRODUCIR i )
- sem_wait(elementos) / un elemento
menos / - sem_wait(mutex)
- dato bufferpos
- pos (pos 1) MAX_BUFFER
- sem_post(mutex)
- sem_post(huecos) / un hueco mas /
- printf("Consume d \n", dato) / consumir
dato / -
- return
41Mutex y variables condicionales
- 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.
42Secciones críticas con mutex
- lock(m) / entrada en la sección crítica /
- / sección crítica /
- unlock(s) / salida de la sección crítica /
- La operación unlock debe realizarla el proceso
ligero que ejecutó lock
43Variables condicionales
- Variables de sincronización asociadas a un mutex
- Conveniente ejecutarlas entre lock y unlock.
- Dos operaciones atómicas
- wait Bloquea al proceso ligero que la ejecuta y
le expulsa del mutex - signal Desbloquea a uno o varios procesos
suspendidos en la variable condicional. El
proceso que se despierta compite de nuevo por el
mutex
44Uso de mutex y variables condicionales
- Proceso ligero A
- lock(mutex) / acceso al recurso /
- / codigo de la sección
- crítica /
- while (condicion FALSE)
- wait(condition, mutex)
- / resto de la sección crítica /
- unlock(mutex)
- Proceso ligero B
- lock(mutex) / acceso al recurso /
- / código de la sección crítica /
- / se modifica la condicción y ésta se hace TRUE
/ - condicion true
- signal(condition, mutex)
- unlock(mutex)
- Importante utilizar while
45Servicios
- 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.
- int pthread_cond_init(pthread_cond_t cond,
- pthread_condattr_t
attr) - Inicializa una variable condicional.
- int pthread_cond_destroy(pthread_cond_t cond)
- Destruye una variable condicional.
46Servicios (II)
- int pthread_cond_signal(pthread_cond_t cond)
- Se reactivan uno o más de los procesos ligeros
que están suspendidos en la variable condicional
cond. - No tiene efecto si no hay ningún proceso ligero
esperando (diferente a los semáforos). - int pthread_cond_broadcast(pthread_cond_t cond)
- Todos los threads suspendidos en la variable
condicional cond se reactivan. - No tiene efecto si no hay ningún proceso ligero
esperando. - int pthread_cond_wait(pthread_cond_t cond,
pthread_mutex_t mutex) - Suspende al proceso ligero hasta que otro proceso
señaliza la variable condicional cond. - Automáticamente se libera el mutex. Cuando se
despierta el proceso ligero vuelve a competir por
el mutex.
47Productor-consumidor con mutex
- define MAX_BUFFER 1024 / tamaño del
buffer / - define DATOS_A_PRODUCIR 100000 / datos a
producir / - pthread_mutex_t mutex / mutex para
controlar el - acceso al buffer compartido /
- pthread_cond_t no_lleno / llenado del buffer
/ - pthread_cond_t no_vacio / vaciado del buffer
/ - int n_elementos / elementos en el
buffer / - int bufferMAX_BUFFER / buffer común /
- main(int argc, char argv)
-
- pthread_t th1, th2
- pthread_mutex_init(mutex, NULL)
-
-
48Productor-consumidor con mutex (II)
- pthread_cond_init(no_lleno, NULL)
- pthread_cond_init(no_vacio, NULL)
- pthread_create(th1, NULL, Productor, NULL)
- pthread_create(th2, NULL, Consumidor, NULL)
- pthread_join(th1, NULL)
- pthread_join(th2, NULL)
- pthread_mutex_destroy(mutex)
- pthread_cond_destroy(no_lleno)
- pthread_cond_destroy(no_vacio)
- exit(0)
-
49Productor-consumidor con mutex (III)
- void Productor(void) / código del productor
/ - int dato, i ,pos 0
- for(i0 i lt DATOS_A_PRODUCIR i )
- dato i / producir dato /
- pthread_mutex_lock(mutex) / acceder
al buffer / - while (n_elementosMAX_BUFFER)/ si
buffer lleno / - pthread_cond_wait(no_lleno,
mutex)/ bloqueo / - bufferpos dato
- pos (pos 1) MAX_BUFFER
- n_elementos
- pthread_cond_signal(no_vacio)/ buffer
no vacío / - pthread_mutex_unlock(mutex)
-
- pthread_exit(0)
50Productor-consumidor con mutex (IV)
- void Consumidor(void) / código del consumidor
/ - int dato, i ,pos 0
- for(i0 i lt DATOS_A_PRODUCIR i )
- pthread_mutex_lock(mutex) / acceder al
buffer / - while (n_elementos 0) / si buffer
vacío / - pthread_cond_wait(no_vacio,
mutex)/ bloqueo / - dato bufferpos
- pos (pos 1) MAX_BUFFER
- n_elementos --
- pthread_cond_signal(no_lleno) / buffer
no lleno / - pthread_mutex_unlock(mutex)
- printf("Consume d \n", dato) /
consume dato / -
- pthread_exit(0)
51Lectores-escritores con mutex
- int dato 5 / recurso /
- int n_lectores 0 / numero de
lectores / - pthread_mutex_t mutex / control del
acceso a dato / - pthread_mutex_t mutex_lectores / control de
n_lectores / - main(int argc, char argv)
-
- pthread_t th1, th2, th3, th4
- pthread_mutex_init(mutex, NULL)
- pthread_mutex_init(mutex_lectores, NULL)
52Lectores-escritores con mutex (II)
- pthread_create(th1, NULL, Lector, NULL)
- pthread_create(th2, NULL, Escritor, NULL)
- pthread_create(th3, NULL, Lector, NULL)
- pthread_create(th4, NULL, Escritor, NULL)
- pthread_join(th1, NULL)
- pthread_join(th2, NULL)
- pthread_join(th3, NULL)
- pthread_join(th4, NULL)
- pthread_mutex_destroy(mutex)
- pthread_mutex_destroy(mutex_lectores)
- exit(0)
-
53Lectores-escritores con mutex (III)
- void Lector(void) / código del lector /
- pthread_mutex_lock(mutex_lectores)
- n_lectores
- if (n_lectores 1)
- pthread_mutex_lock(mutex)
- pthread_mutex_unlock(mutex_lectores)
- printf("d\n", dato) / leer dato /
- pthread_mutex_lock(mutex_lectores)
- n_lectores--
- if (n_lectores 0)
- pthread_mutex_unlock(mutex)
- pthread_mutex_unlock(mutex_lectores)
- pthread_exit(0)
54Lectores-escritores con mutex (IV)
- void Escritor(void) / código del escritor /
-
- pthread_mutex_lock(mutex)
- dato dato 2 / modificar el recurso /
- pthread_mutex_unlock(mutex)
- pthread_exit(0)
-
55Paso de mensajes
- Múltiples soluciones
- Paso de mensajes en POSIX (colas de mensajes)
- Misma máquina (uniprocesador, multiprocesador o
multicomputador) - Mecanismo de nombrado con nombre local
- Identificación identificador especial
- Buffering Sí
- Unidireccional
- Sincronización bloqueante y no bloqueante
- 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(origen, mensaje) recibe un mensaje del
proceso origen
56Colas 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.
57Colas 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 (el de mayor prioridad).
Almacena la prioridad del mensaje en el parámetro
prio - Recepción bloqueante o no.
58Secciones críticas con colas de mensajes
- void main(void)
- mqd_t mutex / cola de mensajes para
sincronizar acceso a la sección crítica / - struct mq_attr attr /atributos cola de
mensajes/ - char c / carácter para sincronizar /
- attr.mq_maxmsg 1 / número máximo mensajes
/ - attr.mq_msgsize 1 / tamaño mensaje /
-
- mutex mq_open(MUTEX'', O_CREATO_RDWR,
0777, attr) - mq_send(mutex, c, 1, 0) / entrar en la
sección - crítica la primera
vez /
59Secciones críticas con colas de mensajes (II)
- if (fork() 0) / proceso hijo /
- for()
- mq_receive(mutex, c, 1, NULL)/entrada
sec. crítica / - / sección crítica /
- mq_send(mutex, c, 1, 0) / salida
sec. critica / -
- else / proceso padre /
- for()
- mq_receive(mutex, c, 1, NULL)/entrada
sec. crítica / - / sección crítica /
- mq_send(mutex, c, 1, 0) / salida
sec. critica / -
-
-
60Productor-consumidor con colas de mensajes
- define MAX_BUFFER 1024 / tamaño del buffer /
- define DATOS_A_PRODUCIR 100000 /datos a
producir/ - mqd_t almacen / cola de mensaje para
almacenamiento - de datos /
- void main(void)
-
- struct mq_attr attr
- attr.mq_maxmsg MAX_BUFFER
- attr.mq_msgsize sizeof(int)
- almacen mq_open("ALMACEN", O_CREATO_RDWR,
0777, attr) -
61Productor-consumidor con colas de mensajes (II)
- if (almacen -1)
-
- perror("mq_open")
- exit(1)
-
- if (fork() 0) / proceso hijo /
- Productor()
- else / proceso padre /
- Consumidor()
- exit(0)
-
62Productor-consumidor con colas de mensajes (III)
- void Consumidor(void)
- int dato
- int i
-
- for(i0
- i lt DATOS_A_PRODUCIR i )
- mq_receive(almacen, dato, sizeof(int),
NULL) - / consumir dato /
- printf("Consume d\n", dato)
-
- return
-
- void Productor(void)
- int dato
- int i
- for(i0
- i lt DATOS_A_PRODUCIR i )
- / producir dato /
- dato i
- printf("Produce d \n", dato)
- mq_send(almacen, dato, sizeof(int),
0) -
- return
-
63Lectores-escritores con colas de mensajes
- struct peticion_t
- int tipo
- char cola100
-
- void lector(char lector) / identificador
lector / - mqd_t controlador / cola proceso
controlador / - mqd_t cola_local / cola para el lector /
- struct mq_attr attr
- struct peticion_t peticion
- attr.mq_maxmsg 1
- attr.mq_msgsize sizeof(struct peticion_t)
- controlador mq_open("CONTROLADOR", O_RDWR)
- cola_local mq_open(lector, O_CREATO_RDWR,
0777, attr)
64Lectores-escritores con colas de mensajes (II)
- peticion.tipo READ
- strcpy(peticion.cola, lector)
- / solicitud de lectura al controlador /
- mq_send(controlador, peticion,
sizeof(peticion), 0) - mq_receive(cola_local, peticion,
sizeof(peticion), NULL) - / leer /
- peticion.tipo OK / fin de lectura /
- mq_send(cola_local, peticion,
sizeof(peticion), 0) - mq_close(cola_local) mq_close(controlador)
mq_unlink(lector) -
- El proceso escritor es similar.
65Lectores-escritores con colas de mensajes (III)
- void Controlador(void)
- mqd_t controlador / cola del proceso
controlador / - struct mq_attr attr
- struct peticion_t peticion
- attr.mq_maxmsg 1
- attr.mq_msgsize sizeof(struct peticion_t)
- controlador mq_open("CONTROLADOR",
O_CREATO_RDWR, 0777, attr) - for ()
- mq_receive(controlador, peticion,
sizeof(peticion), 0) - if (peticion.tipo READ)
- crear_thread(do_read, peticion)
- else
- crear_thread(do_write, peticion)
-
66Lectores-escritores con colas de mensajes (IV)
- void do_write(struct peticion_t pet)
- mqd_t cola_local
- struct peticion_t peticion
- / abre la cola del proceso que realiza la
peticion / - cola_local mq_open(pet-gtcola, O_RDWR)
- pthread_mutex_lock(mutex)
- while (n_lectores gt 0)
- pthread_cond_wait(no_lectores, mutex)
- peticion.tipo OK
- mq_send(cola_local, peticion,
sizeof(peticion), 0) - mq_receive(cola_local, peticion,
sizeof(peticion), NULL) - pthread_mutex_unlock(mutex)
-
- void do_read(struct peticion_t pet)
- mqd_t cola_local
- struct peticion_t peticion
- / abre la cola del proceso que realiza la
peticion / - cola_local mq_open(pet-gtcola, O_RDWR)
- pthread_mutex_lock(mutex)
- n_lectores
- peticion.tipo OK
- mq_send(cola_local, peticion,
sizeof(peticion), 0) - mq_receive(cola_local, peticion,
sizeof(peticion), NULL) - n_lectores --
- if (n_lectores 0)
- pthread_cond_signal(no_lectores)
- pthread_mutex_unlock(mutex)
-
67Servidor multithread con colas de mensajes
68Servidor multithread con colas de mensajes (II)
- / estructura de un mensaje /
- struct mensaje
- char buffer1024 / datos a enviar /
- char cliente256 / cola del cliente /
-
- / mutex y var. condicionales protección de 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 / cola del servidor /
- struct mensaje mess / mensaje a recibir /
- struct mq_attr q_attr / atributos de la cola
/ - pthread_attr_t t_attr / atributos de los
threads / - q_attr.mq_maxmsg 20
- q_attr.mq_msgsize sizeof(struct mensaje)
69Servidor multithread con colas de mensajes (III)
- q_servidor mq_open("SERVIDOR",
O_CREATO_RDONLY, 0700, q_attr) - pthread_mutex_init(mutex_mensaje, NULL)
- pthread_cond_init(cond, NULL)
- pthread_attr_init(t_attr)
- pthread_attr_setscope(t_attr,PTHREAD_SCOPE_SYS
TEM) - pthread_attr_setdetachstate(t_attr,
PTHREAD_CREATE_DETACHED) - while (TRUE)
- mq_receive(q_servidor, mess, sizeof(struct
mensaje), NULL) - pthread_create(thid, t_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)
-
-
70Servidor 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 respuesta / 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/
- mensaje_no_copiado FALSE
- pthread_cond_signal(cond)
- pthread_mutex_unlock(mutex_mensaje)
- / ejecutar la petición del cliente y preparar
respuesta / - / responder al cliente a su cola /
- q_cliente mq_open(mensaje_local.cliente,
O_WRONLY) - mqsend(q_cliente, (char ) respuesta,
sizeof(respuesta), 0) - mq_close(q_cliente)
- pthread_exit(0)
71Ejemplo de código cliente
- struct mensaje / estructura mensaje /
- char buffer1024 / datos envío /
- char cliente256 / cola cliente /
-
- void main(void)
-
- mqd_t q_servidor / cola servidor /
- mqd_t q_cliente / cola cliente /
- struct mq_attr attr / atr. cola /
- struct mensaje peticion / peticion al
servidor / - struct mensaje respuesta / respuesta
del servidor / - attr.mq_maxmsg 1
- attr.mq_msgsize
- sizeof(struct mensaje)
-
- q_cliente mq_open("CLIENTE",
O_CREATO_RDONLY, 0700, 0) - q_servidor mq_open("SERVIDOR", O_WRONLY)
- / preparar peticion /
- mq_send(q_servidor, peticion, sizeof(struct
mensaje), 0) - / esperar respuesta /
- mq_receive(q_cliente, respuesta,
sizeof(struct mensaje), NULL) - mq_close(q_servidor)
- mq_close(q_cliente)
- mq_unlink("CLIENTE")
- exit(0)
-
72Sockets
- Permiten comunicar
- Procesos del mismo computador
- Procesos conectados a través de una red
- Tipos de direcciones
- Direcciones locales dominio UNIX
- Direcciones de red (TCP/IP)
- Dirección de red (dirección IP)
- Puerto
73Sockets (II)
74Resumen
- Pipes
- Mecanismo de comunicación y sincronización
- Mecanismo de nombrado sin nombre
- Identificación descriptor de fichero
- Flujo de datos unidireccional
- Buffering Sí
- Sincronización
- Si pipe vacío ? read() se bloquea
- Si pipe lleno ? write() se bloquea
- FIFOS
- Mecanismo de comunicación y sincronización
- Mecanismo de nombrado con nombre local
- Identificación descriptor de fichero
- Flujo de datos unidireccional
- Buffering Sí
- Sincronización
- Si FIFO vacío ? read() se bloquea
- Si FIFO lleno ? write() se bloquea
75Resumen (II)
- Semáforos POSIX
- Mecanismo de sincronización
- Mecanismo de nombrado sin nombre y con nombre
local - Identificación variable de tipo semáforo
- Mutex y variables condicionales
- Mecanismo de sincronización adecuado para
procesos ligeros - Mecanismo de nombrado sin nombre
- Identificación variables
- Colas de mensajes POSIX
- Mecanismo de comunicación y sincronización
- Mecanismo de nombrado con nombre local
- Identificación identificador especial
- Buffering Sí
- Unidireccional
- Sincronización bloqueante y no bloqueante
76Resumen (III)
- Objetos de memoria compartida
- Mecanismo de comunicación
- Mecanismo de nombrado con nombre local
- Identificación identificador especial
- Sockets
- Mecanismo de comunicación y sincronización
- Mecanismo de nombrado con nombre de red
- Identificación descriptor de fichero
- Buffering Sí
- Sincronización bloqueante y no bloqueante
77Interbloqueos
- Bloqueo permanente de un conjunto de procesos que
compiten por los recursos del sistema o se
comunican entre sí. - Ejemplo Si S y Q con semáforos con valor inicial
- P0 P1
- s_espera(S) s_espera(Q)
- s_espera(Q) s_espera(S)
- . .
- s_abre(S) s_abre(Q)
- s_abre(Q) s_abre(S)
- Ejemplo Si C1 y C2 son dos colas de mensajes
- P0 P1
- receive(C1, M) receive(C2, N)
- . .
- send(C2, M) send(C1, N)
- Condiciones del interbloqueo
- Exclusión mutua
- Retención y espera
- No apropiación
- Espera circular
78Ejemplo
- Ejemplo Si P y Q son semáforos con valor inicial
1 - A B
- s_espera(P) s_espera(Q)
- s_espera(Q) s_espera(P)
- Interbloqueo
79Métodos para tratar con los interbloqueos
- Ignorarlos ? UNIX
- Solucionarlos
- Métodos para prevenir los interbloqueos
- Métodos para evitar los interbloqueos
- Métodos para detectar los interbloqueos