unit uRobotCalculoOptimizadorMulticore_OLD;
{$MODE Delphi}

interface

uses
{$IFDEF WIN32}
  ipcthrd,
{$ELSE}
  uEmuladorWinIPC, uKeyDir,
{$ENDIF}

  xMatDefs, Classes, SysUtils, ugestorsalasmh_OLD;

const
  toSpinlocks = 1000;

type

  TRobotCalculoOptimizadorMultiCore = class(TThread)
  public
    gestorSala: TGestorSalaMH;
    estrellaIni, estrellaFin: integer;
    darPasoAuto: boolean;
    iRobotEnLaLista: integer;
  private
    semCntCalculando, semTareas: TMutex;
    iTareaAsignada: integer;
  public
    constructor Create(gestorSala: TGestorSalaMH; const costoFuturo: TMatOfNReal;
      darPasoAutomaticamente: boolean; iRobotEnLaLista: integer);
    procedure Execute; override;

    function GetProximaTarea: integer;
  end;

  TRangoEstrellas = record
    estrellaIni, estrellaFin: integer;
  end;

  TDAOfTRangoEstrellas = array of TRangoEstrellas;

var
  //mutuoexcluida por semCntCalculando
  cnt_RobotsCalculando: integer;
  //mutuoexcluidas por semTareas
  tareas: TDAOfTRangoEstrellas;
  iProximaTarea: integer;
  nomSemCntCalculando, nomSemTareas, nombreEvPasoCompletoCalculo,
  nombreEvHiloProximoPaso: string;

implementation

constructor TRobotCalculoOptimizadorMultiCore.Create(gestorSala: TGestorSalaMH;
  const costoFuturo: TMatOfNReal; darPasoAutomaticamente: boolean;
  iRobotEnLaLista: integer);
begin
  inherited Create(True);
  //cargarSala se debe hacer secuencial
  self.gestorSala := TGestorSalaMH.Create(nil);
  self.gestorSala.cargarSala(gestorSala.sala.archiSala,
    gestorSala.sala.EscenarioActivo.nombre, True);
  self.gestorSala.sala.idHilo := iRobotEnLaLista + 1;

  self.gestorSala.copiarVarsTiempoEjecucion(gestorSala);

  //  self.sala.nHilos:= sala.nHilos;
  self.gestorSala.sala.estabilizarInicio := False;
  self.gestorSala.sala.inicializarOptimizacion(gestorSala.sala, costoFuturo);
  self.iRobotEnLaLista := iRobotEnLaLista;
  self.darPasoAuto := darPasoAutomaticamente;
  self.FreeOnTerminate := False;
  self.gestorSala.nTareasCalculadasEstePaso := 0;
  self.gestorSala.reenganchar := True;
  self.Start;
end;

function TRobotCalculoOptimizadorMultiCore.GetProximaTarea: integer;
begin
  if not semTareas.Get(toSpinlocks) then
  begin
    writeln('TRobotCalculoOptimizadorMultiCore.Execute: No obtuve semTareas 1');
    Result:= -1;
    Terminate;
  end;
  if iProximaTarea < Length(tareas) then
  begin
    Result := iProximaTarea;
    Inc(iProximaTarea);
  end
  else
    Result := -1;
  semTareas.Release;
end;


procedure TRobotCalculoOptimizadorMultiCore.Execute;
var

{$IFDEF WIN32}
  evPasoCompletoCalculoTx, evProximoPasoRx: TEvent;
{$ELSE}
  evPasoCompletoCalculoTx: TEventTX;
  evProximoPasoRx: TEventRX;
{$ENDIF}

begin
  //Inicialización de variables de mutuoexclusión
{$IFDEF WIN32}
  semCntCalculando := TMutex.Create(nomSemCntCalculando);
  semTareas := TMutex.Create(nomSemTareas);

  evPasoCompletoCalculoTx := TEvent.Create(nombreEvPasoCompletoCalculo, False);
  evProximoPasoRx := TEvent.Create(nombreEvHiloProximoPaso +
    IntToStr(iRobotEnLaLista), False);
{$ELSE}
  semCntCalculando := TMutex.Create(nomSemCntCalculando, 1);
  semTareas := TMutex.Create(nomSemTareas, 1);

  evPasoCompletoCalculoTx := TEventTX.Create(nombreEvPasoCompletoCalculo, 1);
  evProximoPasoRx := TEventRX.Create(nombreEvHiloProximoPaso, iRobotEnLaLista);
{$ENDIF}
  //Fin de inicialización de variables de mutuoexclusión

  gestorSala.nTareasCalculadasEstePaso := 0;

  // obtengo acceso al contador de cnt_RobotsCalculando
  if semCntCalculando.Get(6000) then
  begin
    if cnt_RobotsCalculando = 1 then
      evPasoCompletoCalculoTx.Signal
    else
      Dec(cnt_RobotsCalculando);
    semCntCalculando.Release;
  end
  else
  begin
    writeln('TRobotCalculoOptimizadorMultiCore.Execute: No obtuve semCntCalculando 1');
    Terminate;
  end;

  while (gestorSala.sala.globs.kPaso_ > 0) and (not Terminated) do
  begin

    // Esperamos a que nos autorizen a dar el siguiente paso.
    if not evProximoPasoRx.Wait(60000) then
    begin
      writeln('TRobotCalculoOptimizadorMultiCore.Execute: No me despertaron de evProximoPasoRx');
      Terminate;
      break;
    end;

    iTareaAsignada := GetProximaTarea;
    while iTareaAsignada >= 0 do
    begin
      gestorSala.sala.globs.iTareaEjecutando := iTareaAsignada;

      self.estrellaIni := tareas[gestorSala.sala.globs.iTareaEjecutando].estrellaIni;
      self.estrellaFin := tareas[gestorSala.sala.globs.iTareaEjecutando].estrellaFin;

      gestorSala.sala.calcularRangoEstrellas(estrellaIni, estrellaFin, False, False);
      inc(gestorSala.nTareasCalculadasEstePaso);

      iTareaAsignada := GetProximaTarea;
    end; //while de las tareas

    if not semCntCalculando.Get(toSpinlocks) then
    begin
      writeln('TRobotCalculoOptimizadorMultiCore.Execute: No obtuve semCntCalculando 2');
      Terminate;
      break;
    end;
    if cnt_RobotsCalculando = 1 then
      evPasoCompletoCalculoTx.Signal
    else
      dec( cnt_RobotsCalculando );
    semCntCalculando.Release;

    if darPasoAuto then
      gestorSala.darPaso;
  end; //while de los pasos

  //Liberar variables de mutuoexclusion
  semCntCalculando.Free;
  semTareas.Free;

  evPasoCompletoCalculoTx.Free;
  evProximoPasoRx.Free;

  self.gestorSala.Free;
end;

initialization
{$IFDEF WIN32}
  nomSemCntCalculando := 'nomSemCntCalculando';
  nomSemTareas := 'nomSemTareas';
  nombreEvPasoCompletoCalculo := 'nombreEvPasoCompletoCalculo';
  nombreEvHiloProximoPaso := 'nombreEvHiloProximoPaso';
{$ELSE}
  nomSemCntCalculando := uKeyDir.keyBaseDir + '/nomSemCntCalculando';
  nomSemTareas := uKeyDir.keyBaseDir + '/nomSemTareas';
  nombreEvPasoCompletoCalculo := uKeyDir.keyBaseDir + '/nombreEvPasoCompletoCalculo';
  nombreEvHiloProximoPaso := uKeyDir.keyBaseDir + '/nombreEvHiloProximoPaso';
{$ENDIF}

end.
