Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Thread Programmierung für Downloadmanager (https://www.delphipraxis.net/29089-thread-programmierung-fuer-downloadmanager.html)

mumu 3. Sep 2004 19:47


Thread Programmierung für Downloadmanager
 
hi leute! ich bin zur zeit dabei eine art downloadmanager zu programmieren. dabei verwende ich die TidHttp komponente. ich bekomme aber immer die meldunge ungültiger fensterhandle, obwohl ich alle zugriffe mit criticalsections absichere.

hier einmal der code für einen downloadthread. ich starte in meinem programm bis zu 20 threads, welche die function download aufrufen.

Delphi-Quellcode:
function Download(p: Pointer): Integer;
var parameter: PDownloadParameter;
    weiteredownloads: boolean;
    url: string;
    ordner: string;
    responsestream: TFileStream;
    filename: string;
    doppelter_filename: string;
    doppelt: integer;
    notexists: boolean;
begin
  try
      Parameter := P;
      InterlockedExchangeAdd(Anzahl_der_Threads, 1);

      try
        weiteredownloads := true;
        while (weiteredownloads = true) do
        begin

          try
            // in CriticalSection eintreten, filelist sperren
            EnterCriticalSection(g_cs_gesamt);
              if (filelist.files.Count > 0) and
              (filelist.ordner.Count > 0) and
              (form1.Listview3.Items.Count > 0) then
              begin
                url := filelist.files.strings[0];
                filelist.files.Delete(0);
                ordner := filelist.ordner.strings[0];
                filelist.ordner.Delete(0);
                form1.Listview3.Items.delete(0);
                application.ProcessMessages;
              end else
              begin
                weiteredownloads := false;
              end;
            LeaveCriticalSection(g_cs_gesamt);

            // CriticalSection verlassen
          except
            weiteredownloads := false;
          end;

          if (url = '') or (ordner = '') then
          begin
            weiteredownloads := false;
          end else
          begin
            filename := url;
            delete(filename,1,LastDelimiter('/', filename));
          end;

          EnterCriticalSection(g_cs_gesamt);
            notexists := not fileexists(unit1.currentdir+'\'+ordner+'\'+filename);
          LeaveCriticalSection(g_cs_gesamt);
          if (weiteredownloads = true) and (notexists) then
          begin
            EnterCriticalSection(g_cs_gesamt);
              Parameter.Plabel.Caption := 'Download '+inttostr(Parameter.nr)+': '+filename;
            LeaveCriticalSection(g_cs_gesamt);
            application.ProcessMessages;

            EnterCriticalSection(g_cs_gesamt);
              responseStream := nil;
            LeaveCriticalSection(g_cs_gesamt);
            try
            // in CriticalSection eintreten, filesystem sperren
              EnterCriticalSection(g_cs_gesamt);
                if not directoryexists(unit1.currentdir+'\'+ordner) then
                begin
                  MkDir(currentdir+'\'+ordner);
                end;
                if fileexists(unit1.currentdir+'\'+ordner+'\'+filename) then
                begin
                  doppelt := 0;
                  repeat
                    doppelter_filename := unit1.currentdir+'\'+ordner+'\'+inttostr(doppelt)+filename;
                    doppelt := doppelt + 1;
                  until(not fileexists(doppelter_filename));
                    responseStream := TFileStream.Create(pchar(doppelter_filename), fmCreate);
                end else
                begin
                  responseStream := TFileStream.Create(pchar(unit1.currentdir+'\'+ordner+'\'+filename), fmCreate);
                end;
              LeaveCriticalSection(g_cs_gesamt);
              // CriticalSection verlassen
            except
            end;
            try
              try
                if responseStream <> nil then
                begin
                  application.ProcessMessages;
                  Parameter.dl.Get(url, responseStream);
                  application.ProcessMessages;
                // in CriticalSection eintreten, report sperren
                  EnterCriticalSection(g_cs_gesamt);
                    Succeed(url);
                  LeaveCriticalSection(g_cs_gesamt);
                // CriticalSection verlassen
                end else
                begin
                  // in CriticalSection eintreten, report sperren
                    EnterCriticalSection(g_cs_gesamt);
                      Fail(url, unit1.currentdir+'\'+ordner+'\'+filename);
                    LeaveCriticalSection(g_cs_gesamt);
                  // CriticalSection verlassen
                end;
              except
                // in CriticalSection eintreten, report sperren
                  EnterCriticalSection(g_cs_gesamt);
                    Fail(url, unit1.currentdir+'\'+ordner+'\'+filename);
                  LeaveCriticalSection(g_cs_gesamt);
                // CriticalSection verlassen
              end;
            finally
              responseStream.free;
            end;
          end;
        end;
      finally
      end;
      EnterCriticalSection(g_cs_gesamt);
        Parameter.Plabel.Caption := 'FERTIG!';
        CloseThread();
      LeaveCriticalSection(g_cs_gesamt);
      result := 1;
  except
    Result := 2;
  end;
end;

SleepyMaster 4. Sep 2004 16:38

Re: Thread Programmierung für Downloadmanager
 
application.ProcessMessages; in einm Thread ist soweit ich weiß sehr großer Schwachsinn. Vielleicht kommt daher sogar der Fehler. Ansonsten kann ich dir bei dem kleinen Fetzen Code nicht helfen.

Vielleicht gibst du mal den ganzen Code raus (oder sendest den mir per PM)

Bernhard Geyer 4. Sep 2004 16:45

Re: Thread Programmierung für Downloadmanager
 
Die Delphi VCL-Klassenbibliothek ist nicht Thread-Save. Alle Aktionen welche sich auf Oberflächenelemente beziehen müssen im Kontext des Hauptthreads stattfinden.

Schau in der Delphi-Hilfe mal nach TThread.Synchronize wie du von deinem Thread zugriff auf den Hauptthread hast, um deinen Thread und den "Rest" des Programms zu synchronisieren.

mumu 5. Sep 2004 17:10

Re: Thread Programmierung für Downloadmanager
 
also das application.processmessages ist da normalerweise nicht drin. war blos weil ich was im hauptthread testen wollte. der fehler kommt also nicht daher...

ja es ist mir klar dass die VCL nicht threadsafe ist, daher verwende ich ja critical sections. synchronize ist ja nur beim VCL threadobjekt verfügbar. ich muss aber auf jeden fall mit BeginThread meine threads starten.

mumu 8. Sep 2004 10:01

Re: Thread Programmierung für Downloadmanager
 
also ich hab den code jetzt zu einem TThread-Object umgeändert und statt critical sections hab ich synchronize verwendet. und jetzt funktioniert alles!!! obwohl ich sonst gar nix am quellcode geändert hab. das gibts doch nicht??? ist das im grunde nicht das selbe synchronize und critical sections??? weiß jemand woran das liegt?

danke schonmal

mumu 12. Jan 2005 12:25

Re: Thread Programmierung für Downloadmanager
 
einen alten thread mal wieder nach oben holen!!! ;-) weiß immer noch nicht woran das liegt?

jbg 12. Jan 2005 12:35

Re: Thread Programmierung für Downloadmanager
 
Die CriticalSection synchronisiert nicht mit dem Hauptthread sondern mit sich selbt. Eine VCL-Anweisung in einem Thread wird immer im Kontext des Threads ausgeführt und nicht im Hauptthread. Dazu gibt es TThread.Synchronize, das die übergebe Methode in eine Liste steckt und dann den Thread solange blockiert, bis der Hauptthread in der Botschaftsschleife die Synchronize-Liste abgearbeitet (aufgerufen) hat. Danach geht es im Thread weiter. Der VCL Code in der zu synchronisierenden Methode wird also nicht vom Thread aufgerufen, sondern vom Hauptprogramm und das in der Messageloop.

Luckie 12. Jan 2005 12:41

Re: Thread Programmierung für Downloadmanager
 
Ich hatte noch nie Probleme Kontrolls auf dem Formular aus einem Thread raus anzusprechen. Allerdings übergebe ich sie immer als Parameter an den Thread.

@mumu: Wie ist dein TDownloadParameter Record aufgebaut? Wenn du Strings verwendest, dann dürfen das nur ShortStrings sein.

w3seek 12. Jan 2005 13:56

Re: Thread Programmierung für Downloadmanager
 
Zitat:

Zitat von Luckie
Ich hatte noch nie Probleme Kontrolls auf dem Formular aus einem Thread raus anzusprechen. Allerdings übergebe ich sie immer als Parameter an den Thread.

Da hattest du nur verdammt viel Glück, wie bereits erwähnt ist die VCL selbst nicht thread-safe...


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz