Programación Concurrente: Septiembre 2007 David Fernández-Amorós

Documentos relacionados
1. Equivalencia de herramientas. Implemente las primitivas de los buzones mediante monitores.(2pt).

1. Enunciado. 2. Trabajo del alumno

Examen de Programación Concurrente - Clave: a Junio 2008 Departamento de Lenguajes, Sistemas Informáticos e Ingeniería del Software.

Lección 6: Ejemplos de programación con semáforos

SISTEMAS OPERATIVOS I (Sistemas) / SISTEMAS OPERATIVOS (Gestión) septiembre 2009

Donde Condicion es una expresión booleana, es decir, que puede tomar el valor verdadero (true) o falso (false).

Tipos de datos definidos por el usuario. 1. Arreglos

EXAMENES RESUELTOS DE PROGRAMACION I

PROGRAMACIÓN CONCURRENTE. Tema 5 Monitores

Mientras duerme, el barbero espera a ser despertado por un nuevo cliente.

Práctica de programación concurrente ETSI Informática, UNED David Fernández-Amorós 1.

Práctica de programación concurrente ETSI Informática, UNED David Fernández-Amorós 1.

Instituto de Computación. Facultad de Ingeniería. Universidad de la República Examen de Programación 2 03 de Agosto de 2006 Generalidades:

Universidad de Valladolid. Departamento de informática. Campus de Segovia. Estructura de datos Tema 4: Ordenación. Prof. Montserrat Serrano Montero

Grafo acíclico orientado cuyos nodos corresponden a sentencias individuales.

U nidad 6: A rreglos: U nidim ensionales y m ultidim ensionales

SISTEMAS OPERATIVOS I (Sistemas) / SISTEMAS OPERATIVOS (Gestión) septiembre 2009

EJEMPLO DE PARTIDA. Pongo en la casilla: 4 El tablero queda como: X

PROBLEMAS CLÁSICOS. EL PROBLEMA DE LOS FILÓSOFOS COMENSALES.

Introducción al Lenguaje de Programación Ada

Apunte Laboratorio ALPI - El lenguaje de programación Pascal

Trabajo Práctico Nº 4 Iteración

Programación de Sistemas Concurrentes y Distribuidos 1 a Convocatoria curso 12/13

Equivalencia de herramientas. Implementar las primitivas de los semáforos a partir de las regiones críticas condicionales. (2.5pt)

FUNDAMENTOS DE PROGRAMACIÓN LABORATORIO SESIÓN 2

Uso de recursos compartidos

Este es un arreglo de números enteros, o sea que guarda una serie de variables de tipo INTEGER, todas agrupadas en una sola estructura.

APUNTES DE CÁTEDRA: ARREGLOS MULTIDIMENSIONALES

Concurrencia, exclusión mutua y sincronización. Capítulo 5 HungriaBerbesi

Ejercicios con Monitores

SISTEMAS OPERATIVOS: COMUNICACIÓN Y SINCRONIZACIÓN ENTRE PROCESOS. Procesos concurrentes y problemas en la comunicación y la sincronización

EXAMENES RESUELTOS DE PROGRAMACION I

El problema de los Filósofos

ESTRUCTURA SECUENCIAL ESTRUCTURA SELECTIVA

Primitivas de Sincronización (continuación) MONITORES: Primitiva de alto nivel, es a nivel de lenguajes como: ADA, PASCAL, JAVA.

*** SOLUCIONES *** SISTEMAS OPERATIVOS Examen Parcial 24 de Abril de 2010

Nombre y Apellidos: Especialidad y Grupo:

Departamento de Informática Universidad de Valladolid Campus de Segovia. TEMA 4: TIPOS ABSTRACTOS DE DATOS (TADs)

Arreglos y Subrangos

Calidad del Software. Ejercicios Tema 4 Conceptos de pruebas

Apuntes elaborados por: Aaron Asencio, Eduardo Quevedo, Raquel López Revisado por: Javier Miranda el???

Resolución de Problemas y Algoritmos Clase 6: Repetición (continuación)

Prueba objetiva 2 - Clave b

Lección 10: Ejemplos de programación con semáforos

Programación de Sistemas Concurrentes y Distribuidos 2 a Convocatoria curso 12/13

Secciones críticas y exclusión mutua

Primer Parcial. Programación 1 Instituto de Computación Año 2017

LENGUAJES DE PROGRAMACIÓN. Trabajo Práctico - Junio de 2016

Procesamiento de Lenguajes (PL) Curso 2014/2015. Práctica 1: analizador descendente recursivo

Estructuras de Programación

28/10/2016. Procesamiento de Secuencias. Procesamiento de Secuencias. Procesamiento de Secuencias. Procesamiento de Secuencias

Hay tres juegos, que se juegan utilizando las mismas fichas y tablero, pero con distintas estrategias, y complejidad:

Unidad 1: Gestión de Procesos

REM Visualizar por pantalla los números de Fibonacci REM comprendidos dentro de los límites del intervalo [a,b]. REM

Si L es recursivo, entonces es recursivamente numerable

Programación concurrente

1.2.4 Listas enlazadas

TEMA 7: INICIO A LA PROGRAMACIÓN CON SCRATCH

INICIACIÓN A LA PROGRAMACIÓN: SCRATCH

SISTEMAS OPERATIVOS:

ISO Tema 8,

LENGUAJES DE PROGRAMACIÓN. Trabajo Práctico - Septiembre de 2017

EJERCICIOS PARA EMPEZAR CON PHP

Comunicación y sincronización

El objetivo de este ejemplo es cargar 2 arrays aleatoriamente con Random y después mostrar la suma de esos arrays en un nuevo array.

Tema 2.- Ordenación (Parte I)

Tipos y Estructuras de Control. Dpto. de Ciencias e Ingeniería de la Computación UNIVERSIDAD NACIONAL DEL SUR

Práctica parcial: el juego del pinball, parte 1

Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º

Examen de Lenguajes de Alto Nivel

Programa-Me 2013 Regional on line Problemas

Primer Parcial. Programación 1 Instituto de Computación Año 2011

1. ESTRUCTURA DE UN PROGRAMA PASCAL Todo programa escrito en lenguaje Pascal, del más simple al más complejo, tiene la siguiente estructura:

Módulo. = Asignación = = Comp. de igualdad!= Com. de desigualdad <= Comp. menor o igual >= Comp. mayor o igual AND lógico OR lógica.

Universidad Autónoma del Estado de Hidalgo Instituto de Ciencias Básicas e Ingeniería Área Académica de Computación y Electrónica

Apellidos: Nombre: Matrícula: UNIVERSIDAD POLITÉCNICA DE MADRID

Inicio del programa. Entrada de datos. Proceso de datos. Salida de datos. Fin del programa

Tema 7: Árbol Binario

Tema 1 INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN

Estados de un proceso

col Type mismatch línea 1 3A Type mismatch c$ + j línea 2

Algoritmos y Estructuras de Datos II, Segundo del Grado de Ingeniería Informática, Test de Programación Dinámica, 4 de mayo 2017

1. Lenguaje Pascal. 2. Módulos de un Programa. 3. Tipos de Datos más utilizados. 4. Declaración de Variables

EJERCICIOS DE GRAFOS DE JUEGO

Estudiemos el siguiente problema, propuesto por Wirth y desarrollado por Dijkstra: Una lista de las primeras secuencias que cumplen es:

Tema 6. Gestión de Interbloqueo

UTN FRLP Ing. en Sistemas de Información Algoritmos y Estructura de Datos Trabajos Prácticos Curso 2010

La Máquina de Acceso Aleatorio (Random Access Machine)

FUNDAMENTOS DE OBJECT PASCAL

Estructuras de Control. Secuencia y Selección

Prueba objetiva 2 - Clave a

Prueba objetiva 2 (4F1M) - Clave a

Sentencias iterativas

Arboles. Definiciones formales: 1) un árbol es un grafo acíclico finito T (P, E) tal que. P = E + 1 => todo arco es desconectante.

Ubound y Lbound en Visual Basic. Conocer índice superior e inferior de arrays (arreglos) Ejemplos y ejercicios. (CU00343A)

Ciclos. Recordando Estructuras de Control Básicas: SELECCIÓN (condición) SECUENCIAL

Modelo de Cómputo. Programación concurrente

1. Equivalencia de herramientas. Implemente las primitivas de las regiones críticas condicionales con semáforos. (2pt).

Ingeniería del Software II Ejercicios de OCL

Transcripción:

El juego del laberinto concurrente se juega en un tablero rectangular de n filas y m columnas. En cada casilla puede haber una pared, un espacio vacío o un coco. El objetivo de cada coco es salir del laberinto. Cada casilla tiene como máximo ocho posiciones adyacentes (incluyo las diagonales). Un coco se va movio dentro del tablero, siempre que tenga alguna casilla adyacente libre, hasta que consigue llegar a una de las casillas del rectángulo más externo, que se consideran la salida del laberinto. El desplazamiento sólo es posible a una casilla vacía. Cada coco mantiene una lista de las casillas por las que ha pasado. La siguiente casilla para un coco se calcula de la siguiente manera: Se analizan las direcciones de desplazamiento en el orden de las agujas del reloj, empezando por la dirección arriba y a la izquierda. Si la posición actual es (x,y), entonces la primera dirección es la que lleva a (x-1, y-1), después, la de (x,y-1), a continuación la de (x+1,y-1) y así sucesivamente. La primera dirección que proporcione una casilla libre y que no haya sido visitada se utiliza para moverse. Si todas las casillas vecinas han sido visitadas, entonces se levanta esta restricción y el coco se mueve en la primera dirección, según el orden explicado, en la que haya una casilla libre. Si no se encuentra ninguna casilla libre adyacente, el proceso de evaluación de casillas vuelve a empezar. Las casillas adyacentes no pueden cambiar mientras dura el proceso de evaluación de la situación, pero otros cocos pueden examinar el contenido de esas mismas casillas. Evidentemente, dos cocos distintos no pueden moverse al mismo tiempo hacia la misma casilla. Se pide simular el juego del laberinto concurrente mediante un programa concurrente escrito en pseudocódigo utilizando semáforos. Utilizar un único tipo de proceso: coco. Para seguir la simulación, los cocos deben emitir unos mensajes por pantalla. Cada mensaje debe incluir el número de coco, la posición que ocupa y las posiciones de las casillas que ha visitado. Cada coco debe emitir un mensaje indicando en qué posición del tablero empieza. Esta posición inicial se debe elegir aleatoriamente entre las casillas vacías, o bien al iniciarse el proceso, o bien en el programa principal. También deben emitirse mensajes cada vez que un coco decida moverse, especificando de dónde a dónde se produce el movimiento. Los cocos también deben emitir un mensaje antes de salir del laberinto. La simulación debe contar con unas estructuras de datos que permitan resolver razonablemente el problema. Además, se prestará atención para evitar las situaciones de interbloqueo, inanición y espera activa. Se debe procurar el máximo nivel de concurrencia entre los procesos. Si se identifica un problema-tipo (productores/consumidores o lectores/escritores) debe mencionarse explícitamente (incluyo, en su caso, la prioridad más adecuada) antes de proceder con el pseudocódigo. Es muy importante que el comportamiento de los cocos se ajuste al enunciado, tanto en los aspectos específicamente concurrentes como en los demás. Es muy importante leer con atención el enunciado para responder adecuadamente a lo que se nos pide. En principio, la forma óptima de simular el comportamiento que nos piden depería principalmente de la proporción de paredes frente a casillas vacías y a la 1

proporción de número de cocos frente a número de casillas vacías. Un programa que fuera muy eficiente en un tablero con muchos cocos y pocas casillas libres, donde podría haber varios cocos mirando la misma casilla, no lo sería en otro contexto donde hubiera pocos cocos, y por tanto, pocas posibilidades de que dos cocos quisieran leer la misma casilla al mismo tiempo. Afortunadamente, no tenemos que darle muchas vueltas a esta cuestión: el enunciado nos dice que debe ser posible que varios cocos evalúen la misma casilla. Esto encaja a la perfección con uno de los dos problemas-tipo de la asignatura: lectores y escritores. El esquema de los lectores y escritores es, en la práctica, la única manera en la que varios procesos pueden leer un recurso concurrentemente. Siempre que no se trate de un recurso de sólo lectura, es decir, de un constante. Si es posible que los procesos puedan leer y puedan escribir en un recurso, entonces o bien se bloquea el recurso antes de acceder a el, o bien tenemos un esquema de lectores y escritores, en el que existen unos protocolos de entrada a la lectura y de entrada a la escritura que preparan el acceso al recurso. Un problema bastante frecuente es el de leer variables compartidas sin pedir exclusión mutua. Esto es un error porque como hemos señalado en el párrafo anterior, si hay un proceso que puede modificar la variable, no podremos saber que el valor que hemos leído es correcto, tampoco podremos saber si ha cambiado desde el momento de la lectura. Otra cuestión interesante es la de la granularidad. Una posibilidad, un tanto simplista, es considerar el tablero como un único recurso. Otra posibilidad que aumenta considerablemente la concurrencia es considerar que cada casilla es un recurso distinto. Lo bueno de este enfoque es que no es mucho más complicado. Se trata de aplicar el esquema lectores y escritores a cada casilla. En este caso, hemos elegido la prioridad para la escritura, con el fin de evitar la inanición, aunque también hay argumentos a favor de la prioridad para la lectura. program laberinto de cocos; const N = 10; M = 15; Ncocos = 10; // Arrays para calcular facilmente las casillas adyacentes vecinas_x = {-1,0,1,1,1,0,-1,-1}; vecinas_y = {-1, -1, -1, 0, 1, 1, 1, 0}; var mutex_mensaje : semaphore; // Las variables del modelo de lectores y escritores mutex, lector, escritor : array [1..N, 1..M] of semaphore; nl, nle, nee : array [1..N, 1..M] of integer; escribio : array[1..n, 1..M] of boolean; // Variables para indices de bucles; i,j : integer; // Para guardar las posiciones iniciales de los cocos, // no se usan fueran del programa principal coordenada_x, coordenada_y : array[1..ncocos] of integer; tablero : array[1..n][1..m] of { vacia, pared, uncoco } 2

procedure entrada_lectura(x,y : integer); // Si se está escribio o existen escritores en espera // el lector debe ser bloqueado if (escribio[x,y] or nee[x,y] > 0) then nle[x,y] := nle[x,y] + 1; wait(lector[x,y]) nle[x,y] := nle[x,y] - 1; nl[x,y] := nl[x,y] + 1; if (nle[x,y] > 0) then // Desbloqueo encadenado signal(lector[x,y]) signal(mutex[x,y]) ; // entrada_lectura procedure entrada_escritura(x,y : integer); // Si se está escribio o existen lectores el escritor // debe ser bloqueado if (nl[x,y] > 0 or escribio[x,y]) then nee[x,y] := nee[x,y]+ 1; wait(escritor[x,y]); nee[x,y] := nee[x,y]- 1; escribio[x,y] = true; signal(mutex[x,y]) ; // entrada_escritura procedure salida_lectura(x,y : integer); nl[x,y] := nl[x,y] - 1; // Desbloquear un escritor si es posible if (nl[x,y] = 0 and nee[x,y] > 0) then signal(escritor[x,y]); ;// salida_lectura procedure cierra_escritura(x,y : integer); escribio[x,y] = false; // Desbloquear un escritor que esté a la espera. // Si no, desbloquear un lector en espera if (nee[x,y] > 0) then signal(escritor[x,y]); if (nle[x,y] > 0) then signal(lector[x,y]); // cierra_escritura process type coco(id : integer, coor_x, coor_y : integer); var l,k : integer; // Variables para bucles // La tabla es para uso interno del proceso, //la lista es para imprimir las casillas por las que paso tabla_visitadas : array[1..n][1..m] of boolean; lista_visitadas : array[1..maxlon] of record x,y : integer ; lon_visitadas : integer; // Longitud de la lista de visitadas // En la primera vuelta de inspección de las casillas adyacentes importa // si las hemos visitado ya o no, en la segunda vuelta no importa_visitadas : boolean; salir_de_bucle : boolean; // Nos dice si ya nos hemos movido de casilla o no estoy_mirando_casilla_adyacente_numero : integer; coordenada_x, coordenada_y, candidata_x, candidata_y : integer; 3

procedure escribir_lista_visitadas; var k : integer; for k := 1 to lon_visitadas do write('(', lista_visitadas.x[k], ','. lista_visitadas.y[k], ') '); writeln; ; // escribir_lista_visitadas coordenada_x := coor_x; coordenada_y := coor_y; for l:= 1 to N do for k:= 1 to M do tabla_visitadas = false; lon_visitadas = 1; // Primer mensaje wait(mutex_mensaje); writeln( Hola, soy el coco número ',id, y he comenzado en la posición (',coordenada_x,,,coordenada_y, ) ); signal(mutex_mensaje); tabla_visitadas[coordenada_x, coordenada_y] := true; lista_visitadas[lon_visitadas].x := coordenada_x; lista_visitadas[lon_visitadas].y := coordenada_y; // Mientras no estemos en el rectángulo del borde, es decir, en posición de terminar... while coordenada_x > 1 and coordenada_x < N and coordenada_y > 1 and coordenada_y < M) importa_visitadas := true; salir_del_bucle := false; while not salir_del_bucle estoy_mirando_casilla_adyacente_numero := 1; while estoy_mirando_casilla_adyacente_numero < 9 and not salir_de_bucle candidata_x := coordenada_x + vecinas_x[estoy_mirando_casilla_adyacente_numero]; candidata_y := coordenada_y + vecinas_y[estoy_mirando_casilla_adyacente_numero]; if (importa_visitadas and tabla_visitadas[candidata_x][candidata_y] = false) or not importa_visitadas then // Miramos si la casilla candidata esta vacia entrada_lectura(candidata_x, candidata_y); if (tablero[candidata_x, candidata_y] = vacia) then salida_lectura(candidata_x, candidata_y); // Pedimos bloqueo de escritura sobre la candidata // y sobre la casilla actual entrada_escritura(candidata_x,candidata_y); 4

entrada_escritura(coordenada_x,coordenada_y); // Hay que darse cuenta de que despues de soltar el bloqueo // de lectura, otro coco puede haberse movido a la casilla, // por lo que nos toca comprobar si sigue vacía despues de // obtener el bloqueo de escritura. // Si la casilla candidata sigue vacia... if (tablero[candidata_x, candidata_y] = vacia) then tablero[candidata_x, candidata_y] := uncoco; tablero[coordenada_x, coordenada_y] := vacia; salida_escritura(coordenada_x, coordenada_y); salida_escritura(candidata_x, candidata_y); wait(mutex_mensaje); write( Soy el coco,id, y me muevo de la casilla (,coordenada_x,,, coordenada_y, ) hasta la (, candidata_x,,, candidata_y, ) y he pasado ya por: ); escribir_lista_visitadas; signal(mutex_mensaje); coordenada_x := candidata_x; coordenada_y := candidata_y; tablas_visitadas[coordenada_x, coordenada_y] := true; lon_visitadas := lon_visitadas + 1; lista_visitadas[lon_visitadas].x := coordenada_x; lista_visitadas[lon_visitadas].y := coordenada_y; salir_del_bucle := true; salida_escritura(coordenada_x, coordenada_y); salida_escritura(candidata_x, candidata_y); ; // if tablero[...] = vacia salida_lectura(candidata_x, candidata_y); // if (importa_visitadas...) estoy_mirando_casilla_adyacente_numero := estoy_mirando_casilla_adyacente_numero + 1; // while estoy_mirando_casilla_adyacente_numero if importa_visitadas = true then // Hemos terminado la primera vuelta de inspeccion // y seguimos sin casilla para mover importa_visitadas := false; // Hemos hecho las dos vueltas y no hemos encontrado nada salir_del_bucle := true; // while not salir_de_bucle; // while coordenada_x... wait(mutex_mensaje); writeln ( Soy el coco,id, como ya he llegado al borde del tablero me voy ); signal(mutex_mensaje); // process coco 5

var cocos : array[1..ncocos] of coco; // Programa principal for i:=1 to N do for j:=1 to M do tablero[i][j] := vacia; // Codigo para poner las paredes en su sitio... // Paredes colocadas init(mutex_mensaje, 1); // Ahora elegimos unas coordenadas iniciales para los cocos for i := 1 to Ncocos do repeat // Elegimos al azar dos numeros. La coordenada x entre 2 y N-1 y la y entre 2 y M - 1, // no queremos que la posición inicial esté en la zona de salida del tablero coordenada_x[i] = random (2..N-1); coordenada_y[i] = random(2..m-1); until tablero[coordenada_x[i]][coordenada_y[i]] = vacia; tablero[coordenada_x[i]][coordenada_y[i]] = uncoco; ; // Inicializamos las estructuras para los lectores y escritores for i:= 1 to N do for j:= 1 to M do init(mutex[i,j],1); init(escritor[i,j], 0); init(lector[i,j], 0); nl[i,j] = 0; nle[i,j] = 0; nee[i,j] = 0; escribio[i,j] = false; co for i := 1 to Ncocos do cocos[i] = coco(i, coordenada_x[i], coordenada_y[j]); co. 6