Tipos de Datos. Pipe (Tubería)

Table of Contents [hide]

Introducción

Un pipe o tubería es una estructura de datos que representa un canal de comunicación con una estructura de tipo FIFO (primero en entrar, primero en salir).

La denominación de tubería (en ingles pipe) viene del concepto de que los datos que introducimos o empujamos por un extremo de la tubería "aparecen" en el extremo contrario. Si realizamos una operación de lectura en la tubería y no hay datos en esta el hilo llamante se quedará bloqueado hasta que haya datos. Si realizamos una escritura en la tubería y esta ha alcanzado su tamaño máximo el proceso que desea escribir en la tubería se quedará bloqueado hasta que algun lector saque un dato.

Vamos a definir dos operaciones básicas sobre la tubería, Read y Write, Write esperará indefinidamente si el pipe está lleno mientras que Read aceptará un parametro que indicará el tiempo máximo de espera en la lectura. Para señalizar cuando hay datos en el pipe y cuando esta lleno usaremos sendos objetos TEvent.

El código

unit uPipe;

interface

uses
  Classes, SysUtils, SyncObjs, Windows;

type TPipe = class
  protected
    // La lista que almacena los objetos del pipe
    FList : TThreadList;
    // Identifica el máximo tamaño del pipe
    FMaxSize : Integer;
    // El evento usado para indicar la presencia de
    // datos en el pipe.
    FHayDatos : TEvent;
    // El evento usado para indicar que hay espacio
    // en el pipe
    FHayEspacio : TEvent;
  public
    constructor Create(Size : Cardinal);
    { Escribe un objeto en el pipe
      Devuelve -1 si error, 0 en otro caso
    }

    function Write(obj : TObject) : integer;

    function Read(timeout : cardinal) : TObject;
end;

implementation

{ TPipe }

constructor TPipe.Create(Size: Cardinal);
begin
  FList := TThreadList.Create;
  FMaxSize := Size;
  // AutoResetEvent, desactivado de inicio
  FHayDatos := TEvent.Create(nil,false,false,'');
  // ManualResetEvent, activado de inicio
  FHayEspacio := TEvent.Create(nil,true,true,'');
end;

function TPipe.Read(timeout: cardinal): TObject;
var
  res : TWaitResult;
  list : TList;
  EstabaLleno : boolean;
begin
  res := FHayDatos.WaitFor(timeout);
  case res of
    wrSignaled :
      begin
        // Proteger el acceso y devolver el objeto
        list := FList.LockList;
        try
          EstabaLleno := list.Count = FMaxSize;
          result := list[0];
          list.Delete(0);
          if EstabaLleno then
            FHayEspacio.SetEvent; // Ya no está lleno
          if list.Count >; 0 then
            FHayDatos.SetEvent; // Aún quedan datos
        finally
          FList.UnlockList;
        end;
      end;
    else
      result := nil;
  end;
end;

function TPipe.Write(obj: TObject) : integer;
var
  res : TWaitResult;
  list : TList;
begin
  // Esperar si el pipe esta lleno
  res := FHayEspacio.WaitFor(INFINITE);
  case res of
    wrSignaled:
      begin
        list := FList.LockList;
        try
          list.Add(obj);
          FHayDatos.SetEvent; // Ahora hay datos
          if list.Count = FMaxSize then
            FHayEspacio.ResetEvent; // Esta lleno
        finally
          FList.UnlockList;
        end;
        result := 0;
      end
    else
      result := -1;
  end;
end;
8
Average: 8 (3 votes)
Your rating: None