Hoja de ruta: concurrencia Esta es una lista de ejercicios sencillos de coordinación de procesos que sirve de plan de adiestramiento en el tema de concurrencia. 1 Comentar la validez del siguiente programa como solución al problema de la sección crítica para dos procesos: Variables enteras globales: n1 y n2 inicializadas a 0 proceso P1 proceso P2 while (true) { Sección no crítica n1 = 1; n1 = n2+1; while ((n2!=0) && (n2<n1)) {}; Sección Crítica1 n1 = 0; Sección no crítica } while (true) { Sección no crítica n2 = 1; n2 = n1+1; while ((n1<>0) && (n1<=n2)) {}; Sección Crítica2 n2 = 0; Sección no crítica } 2 Supongamos que tenemos N procesos que ejecutan el siguiente código: Proceso Pi { ... Sección no crítica de Pi ... Sección crítica de Pi ... Sección no crítica de Pi } Diseñar una solución al problema de la sección crítica de los procesos empleando semáforos. 3 Sean P1 y P2 dos procesos concurrentes. Modificar el código de ambos procesos de forma que el conjunto de sentencias R2 del proceso 2 se ejecute después de que se haya ejecutado el conjunto de sentencias S1 del proceso 1. Proceso P1 { S1; S2; } Proceso P2 { R1; R2; } © 2008-2015 A. Quesada, C.R. García, F. Santana, J.M. Santos 4 Supongamos tres procesos concurrentes P1, P2 y P3 con el código que se muestra a continuación: Proceso P1: while (true) { a; b; } Proceso P2: while (true) { c; d; } Proceso P3: while (true) { e; f; } Empleando semáforos, se pide introducir las modificaciones necesarias para que por cada ejecución de «a» o de «e» se permita ejecutar una iteración de «d». 5 En una tienda de pájaros están teniendo problemas para tener a todos sus canarios felices. Los canarios comparten una jaula en la que hay un plato con alpiste y un columpio para hacer ejercicio. Todos los canarios quieren inicialmente comer del plato y después columpiarse. Pero se encuentran con el inconveniente de que sólo tres de ellos pueden comer del plato al mismo tiempo y sólo uno puede columpiarse. Define un proceso que ejecuten los canarios concurrentemente de forma que sincronicen sus actividades usando semáforos. 6 En una fábrica se tienen dos procesos que modelan una planta embotelladora de bebidas, y que trabajan en paralelo: • Un proceso «Embotellador» se encarga de preparar botellas de un litro. • Otro proceso «Empaquetador» se encarga de empaquetar y reponer las cajas donde se van colocando las botellas. Cada vez que el embotellador prepara una botella, ésta se coloca en una caja, que tiene una capacidad de 10 litros. Si al colocar la botella, la caja queda llena, se envía una señal al empaquetador, que toma la caja, la sella y la guarda en un almacén. El empaquetador deposita una nueva caja de 10 litros, totalmente vacía. Mientras el empaquetador está haciendo su labor, el embotellador no puede colocar sus botellas, ya que en esos momentos no hay una caja disponible. Encontrar una solución basada en semáforos que sincronice el problema de concurrencia citado. 7 Se trata de resolver el problema de la pajarería (problema 5) haciendo una jaula un poco más entretenida. Vamos a permitir que se puedan columpiar dos canarios, siempre y cuando uno sea macho y otro hembra. Nota: No respondemos del uso que le den los canarios al columpio☺ © 2008-2015 A. Quesada, C.R. García, F. Santana, J.M. Santos 8 Vamos a simular un conjunto de N procesos que juegan al famoso juego adolescente-alcohólico del «marcianito». En este juego, un grupo de personas se reúnen en círculo; cada una tiene un número entre 1 y N. El número 1 agita sus dos manos al lado de su cabeza al grito de «marcianito número 1 llamando a marcianito número XXX», a lo que la persona con el número XXX debe contestar con un mensaje similar «marcianito número XXX llamando a marcianito número YYY», y así hasta que alguien se despiste. Se trata de hacer una simulación del sistema usando semáforos, en la que cada proceso i tendrá la siguiente estructura (i será un número entre 1 y N): Proceso Pi: while (true) { marcianito ( i, random(1..N) ); } La rutina marcianito(i,j) debe funcionar así: el proceso i espera a que alguien le ceda el turno; una vez que le han cedido el turno, imprime por pantalla «marcianito número i llamando a marcianito número j». Y a continuación, cede el turno al proceso j, que hasta ese momento habrá estado bloqueado dentro de la rutina marcianito(j,otro_proceso). Además, el marcianito número 1 es el que arranca el sistema. Es decir, que en su primera iteración, el proceso 1 no debe esperar a que nadie le ceda el turno. NOTA: lo que hay que implementar es únicamente la rutina marcianito(i,j). 9 Dados los procesos descritos en el ejercicio 4, introducir las modificaciones necesarias para conseguir que si M es el número de veces que «a» se ha ejecutado y N es el número de veces que «e» se ha ejecutado, entonces «d» puede ejecutarse hasta min(M,N) veces sin bloquearse. 10 Resolver el problema 4 utilizando UN SOLO semáforo binario. Nota: Pueden usar cualquier estructura algorítmica, variables, etc. pero sólo un semáforo. 11 Suponga un recurso que debe ser usado de manera exclusiva por parte del proceso que lo utiliza. En el sistema se ejecutan siempre los mismos procesos que son N, identificándose cada uno de ellos por un valor entero cuyo rango es de 1 a N. Estos procesos necesitan para cumplir con su cometido hacer uso del recurso compartido. Cuando un proceso necesita utilizar el recurso lo solicita mediante la función: void Solicito_Recurso (int Mi_Id_Proc); de forma que si el recurso está ocupado deberá esperar hasta que quede libre. Cuando varios procesos solicitan el uso del recurso, se le concederá a aquel proceso cuyo identificador es el más pequeño. Cuando se libera el recurso, el proceso que lo libera lo hace con la función: void Libero_Recurso (int Mi_Id_Proc); Implementar las funciones Solicito_Recurso y Libero_Recurso empleando semáforos. 12 Se dispone de una base de datos a la que se puede acceder mediante múltiples hilos concurrentes. Sobre la base de datos pueden ejecutarse tres operaciones: leer, escribir y administrar. Las operaciones han de cumplir las siguientes reglas de coordinación: © 2008-2015 A. Quesada, C.R. García, F. Santana, J.M. Santos Se permiten lecturas concurrentes. En cada momento sólo puede haber activa una operación de escritura. Mientras se ejecuta una operación de escritura, no se puede realizar ninguna lectura. Mientras se ejecutan operaciones de lectura, no se puede realizar ninguna escritura. La operación de administrar se puede ejecutar en cualquier momento y puede solaparse con las operaciones de lectura o de escritura que estén realizándose en ese momento. Pueden realizarse varias operaciones de administración concurrentes. Mientras se está realizando alguna operación de administración, las nuevas solicitudes de lectura o de escritura deben mantenerse en espera. Escribir un algoritmo que coordine correctamente la ejecución de las tres operaciones, utilizando semáforos como herramienta de sincronización. 13 Resolver estos problemas clásicos de sincronización usando exclusivamente semáforos binarios: búfer limitado; primer problema de los lectores y escritores; filósofos comensales. 14 Suponga un sistema que dispone de N impresoras idénticas que se quieren gestionar de la siguiente manera: Los procesos cuando quieren utilizar una impresora deben pedírselo al sistema operativo mediante una función llamada Pido_Impresora(proceso) de forma que si hay disponible se le concede y si no, el proceso debe esperar hasta que haya una impresora disponible. El parámetro proceso es un número entero que identifica al proceso que invoca a la función. Un proceso puede tener asignada una impresora como máximo. En caso de que teniendo una impresora asignada vuelva a pedir otra impresora, la rutina Pido_Impresora() deberá retornar -1. Los procesos liberan de forma voluntaria la impresora mediante la llamada Libero_Impresora(proceso). El parámetro proceso es un número entero que identifica al proceso que invoca a la función. Si un proceso intenta liberar una impresora que no le ha sido asignada, la rutina Libero_Impresora() deberá retornar -1. Se pide implementar la estructura general de las rutinas Pido_Impresora() y Libero_Impresora() empleando semáforos. 15 Se ha inaugurado un nuevo parque en el barrio y debido a la gran aceptación se ha establecido un aforo máximo de usuarios (N) por razones de seguridad. Para ello se han instalado unos torniquetes a la entrada y a la salida que controlan en todo momento el número de personas en el parque. Cuando el aforo está completo, se debe esperar en la entrada hasta que alguien salga del parque. La afluencia de gente es tal que se forman largas colas de espera, por lo que se ha decidido crear una entrada preferente para los vecinos residentes en la zona, de forma que cuando el parque está lleno, tienen preferencia sobre los no residentes a la hora de acceder a las instalaciones. Se pide realizar el código de entrada y salida del parque, de forma que cuando alguien abandona el parque, en caso de que existan personas esperando debido a que el cupo esté agotado, tendrán preferencia los residentes frente a los no residentes. La sincronización se deberá realizar con semáforos. © 2008-2015 A. Quesada, C.R. García, F. Santana, J.M. Santos