Página 1 de 1

Filósofos comiendo

NotaPublicado: Vie Mar 06, 2009 17:03
por Flash_noi
Hola,

he implementado una solución del típico problema de los filósofos comiendo. Quería ponerlo aquí para discutir sobre el problema, la solución expuesta y su implementación. Saludos!

Los archivos se pueden descargar desde aquí.

Especificación objeto protegido Cubierto
Código: Seleccionar todo
package Cubiertos is

  type Cubierto is limited private;
   
   procedure Coger(C: in out Cubierto);
   procedure Soltar(C: in out Cubierto);

private
   
   type Status is (LIBRE, OCUPADO);
   
   protected type Cubierto(Estado_Cubierto: Status := LIBRE) is
      entry Coger;
      entry Soltar;
   private
      Estado: Status := Estado_Cubierto;
   end Cubierto;
   
end Cubiertos;


Implementación objeto protegido Cubierto
Código: Seleccionar todo
package body Cubiertos is

   
   procedure Coger (C: in out Cubierto) is
   begin
      C.Coger;
   end Coger;

   procedure Soltar (C: in out Cubierto) is
   begin
      C.Soltar;
   end Soltar;

   protected body Cubierto is

      entry Coger when Estado = LIBRE is
      begin
         Estado := OCUPADO;
      end Coger;


      entry Soltar when Estado = OCUPADO is
      begin
         Estado := LIBRE;
      end Soltar;

   end Cubierto;

end Cubiertos;


Programa Principal. Creación de tareas Filósofo
Código: Seleccionar todo
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Cubiertos; use Cubiertos;

procedure Problema_Filosofos is
   
   type PCubierto is access Cubierto;
   
   task type TFilosofo(Id: Character; Cubierto1: PCubierto; Cubierto2: PCubierto);
   
   task body TFilosofo is
     
      procedure Comer is
      begin
         Coger(Cubierto1.all);
         Coger(Cubierto2.all);
         for i in 1..10 loop
            Put(Id & "c ");
            delay 1.0;
         end loop;
         Soltar(Cubierto2.all);
         Soltar(Cubierto1.all);
      end Comer;
     
      Procedure Pensar is
      begin
         for i in 1..10 loop
            Put(Id & "p ");
            delay 1.0;
         end loop;
      end Pensar;
     
   begin
      loop
         Comer;
         Pensar;
      end loop;
   end TFilosofo;
     
   Num_Cubiertos: Positive;
   
begin

   Put("Introduce el numero de cubiertos: "); Get(Num_Cubiertos); New_line;
   
   declare
      type PTFilosofo is access TFilosofo;
      P: PTFilosofo;
      C: Character := 'A';
      Cuberteria: array (1..Num_Cubiertos) of PCubierto;
   begin
      for i in 1..Num_Cubiertos loop
         Cuberteria(i) := new Cubierto;
      end loop;
     
      for i in 1..Num_Cubiertos-1 loop
        P := new TFilosofo(C, Cuberteria(i), Cuberteria(i+1));
        C := Character'Succ(C);
      end loop;
      P := new TFilosofo(C, Cuberteria(1), Cuberteria(Num_Cubiertos));
   end;

Re: Filósofos comiendo

NotaPublicado: Vie Mar 06, 2009 22:22
por gneuromante
Flash_noi, yo lo veo una implementación bastante natural: un tipo protegido para los recursos compartidos y varias tareas para realizar las acciones concurrentes sobre ellos. Quizá lo único que no sea muy ortodoxo, aunque en este ejemplo no tiene ninguna implicación, es el hecho de estar perdiendo las referencias a los filósofos. Quizá sería mejor tener otro array de PTFilosofo, igual que lo tienes de los cubiertos.

Lo podrías poner en el wikilibro, quedaría bien junto al problema del barbero durmiente: http://es.wikibooks.org/wiki/Programación_en_Ada_/_Tareas_/_Ejemplos#Problema_del_barbero_durmiente

Si lo prefieres, te lo puedo poner yo, que ya conozco el sistema wiki.

Re: Filósofos comiendo

NotaPublicado: Sab Mar 07, 2009 14:43
por Flash_noi
Hola,

Vale cuélgalo si quieres. Lo colgué para poder hablar de los diferentes temas, da mucho juego. Desde la implementación hasta el propio algoritmo, ¿por qué no produce Deadlock? etc...

A medida que vayamos descubriendo los matices se puede ir comentando el código para que pueda servir de "libro de texto".

Saludos!!

Re: Filósofos comiendo

NotaPublicado: Sab Mar 07, 2009 22:07
por gneuromante
Lo que evita que haya deadlock es que el último filósofo coge los cubiertos al revés y de ese modo no se quedan todos los filósofos con su primer cubierto en la mano.

Es gracioso cambiar el orden del último filósofo de este modo:
Código: Seleccionar todo
      P := new TFilosofo(C, Cuberteria(Num_Cubiertos, Cuberteria(1)));

y ver como terminan en bloqueo mutuo. Para verlo antes de que nos aburramos es mejor quitar los delays. En la otra situación incluso con delays no ocurre.