Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: [Threads] Textureloader - Einige Fragen

  Alt 20. Nov 2008, 23:26
Ahja, WaitforSingleObject. Man kann ja auch auf Threads, Processe, Semaphore ... warten.

Ich würde die ThreadObjectQueue im Textureloader erstellen und zerstören. Ich bastel mal alles zusammen und baue ein Event ein. Keine Garantie, dass es direkt so funktioniert
Delphi-Quellcode:
type
  TThreadQueue = class(TObjectQueue)
    private
      FLock: TRTLCriticalSection; //Es gibt auch die Klasse TCriticalSection, aber es besteht kein Unterschied zur direkten Verwendung der WinAPI-Funktionen
      FEvent: TEvent; //Wie bei der Critical Section, kannst du hier auch direkt die WinAPI nutzen; in der Klasse TEvent sind ein paar Vereinfachungen
    public
      constructor Create;
      destructor Destroy; override;

      function Push(AObject: TObject): TObject;
      function Pop: TObject;
      function Peek: TObject;

      property Event:TEvent read FEvent;
  end;

[...]

constructor TThreadQueue.Create;
begin
  inherited Create;
  InitializeCriticalSection(FLock)
  FEvent:=TEvent.create; //evtl. initialisieren?
end;

destructor TThreadQueue.Destroy;
begin
  EnterCriticalSection(FLock);
  try
    while (List.Count <> 0) do
      (inherited Pop).Free;
    FEvent.free;
    inherited Destroy;
  finally
    LeaveCriticalSection(FLock);
    DeleteCriticalSection(FLock);
  end;
end;

function TThreadQueue.Push(AObject: TObject): TObject;
begin
  //neues Objekt in der Klasse, also Event feuern
  EnterCriticalSection(FLock);
  try
    Result := inherited Push(AObject);
    FEvent.SetEvent;
  finally
    LeaveCriticalSection(FLock);
  end;
end;

function TThreadQueue.Pop: TObject;
begin
  EnterCriticalSection(FLock);
  try
    Result := inherited Pop;
  finally
    LeaveCriticalSection(Flock);
  end;
end;

function TThreadQueue.Peek: TObject;
//Was jetzt peek macht, weis ich nicht, deswegen ändere ich hier nix
begin
  EnterCriticalSection(FLock);
  try
    Result := inherited Peek;
  finally
    LeaveCriticalSection(FLock);
  end;
end;
Delphi-Quellcode:
 TTextureLoader = class(TThread)
    private
      FQueue: TThreadQueue
      FCurJob: TJob; // Aktueller Job (für die Synchronize-Prozeduren)

      procedure SyncGenTex;
      procedure SyncFailed;
      procedure SyncSucceeded;
    public
      constructor Create;
      destructor Destroy; override;

      

      procedure AddTexture(Path: String; Texture: TglBitmap2D;
                           OnFinish: TFinishProc = nil);
    protected
      procedure DoTerminate; override; //Hier muss noch das Event gesetzt werden, sondet endet der Thread nicht
      procedure Execute; override;
  end;

[...]
  
procedure TTextureLoader.AddTexture(Path: string; Texture: TglBitmap2D;
                                    OnFinish: TGFinishProc = nil);
// Das Texture-Objekt wird immer schon vor Aufruf dieser Funktion angelegt.
// OnFinish bietet die Möglichkeit, "Bescheid" zu geben, wenn die Textur fertig ist oder nicht geladen werden kann
var
  Job: TJob;
begin
  if FileExists(Path) and Assigned(Texture) then begin
    Job := TJob.Create;
    Job.Path := Path;
    Job.Texture := Texture;
    Job.OnFinish := OnFinish;

    FQueue.Push(Job);

    // Falls Thread angehalten wurde, wieder aufnehmen
    //das macht jetzt die Queue. Du kannst natürlich SetEvent hier aufrufen und generell in die ThreadKlasse legen; weis nicht, was besser ist.
  end;
end;

procedure TTextureLoader.Execute;
begin
  while not Terminated do begin

    // Schlafen legen, wenn keine Jobs mehr vorhanden sind, um den Thread zu erhalten
    if (FQueue.Count = 0) then
      FQueue.Event.Waitfor(infinite); // = waitforsingleobject ohne Zeitbegrenzung
      //hier bei nochmal auf terminated abfragen
    else begin
      //hier evtl. Event.ResetEvent aufrufen

      FCurJob := MTGJob(fQueue.Pop);

      // Eventuell noch ein try..finally rumbasteln, um FCurJob sicher freizugeben und einen Fehler in SyncFailed abzufangen
      try
        FCurJob.Texture.LoadFromFile(FCurJob.Path);
        Synchronize(SyncGenTex);

        Synchronize(SyncSucceeded);
        FCurJob.Free;
      except
        on E: Exception do
          Synchronize(SyncFailed);
      end; // try..except
    end; // if..then..else

  end; // while
end;

procedure TTexturLoader.DoTerminate;
begin
  inherited;
  FQueue.Event.setevent;
end;
Ich denke, ich habe nix vergessen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat