Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Update-Vorgang in einen Thread auslagern (https://www.delphipraxis.net/183191-update-vorgang-einen-thread-auslagern.html)

mm1256 18. Dez 2014 12:04

Update-Vorgang in einen Thread auslagern
 
Hallo Delphianer,

vorsicht, es wird ein kleiner Roman, aber, ich versuche so weit es geht Missverständnisse und sicher auch gut gemeinte Vorschläge über Alternativen von vorneherein auszuschließen. Und dazu braucht es eben auch ein paar Zeilen.

Ich habe für meine SW ein Update-Programm, das über ein mit Blowfish gesichertes TCP/IP-Protokoll eine Datenbank-Verbindung zu meinem Update-Server (NexusDB-Server) herstellt, eventuell neuere Dateien herunterlädt, und dann installiert. Der selbe DB-Server (nur eine andere Datenbank) wird für die Bereitstellung der Lizenzen verwendet. Soweit nichts besonderes. Läuft auch seit 2 Jahren prima.

Wenn ich meine SW mit meinem selbst geschriebenen Installationsprogramm installiere, ist der Ablauf (Ausschnitt) wie folgt:

1. Der User gibt die Lizenznummer ein
2. Die Lizenz(datei) wird heruntergeladen
3. Installation wird fortgesetzt

Nach der Installaton wird meine SW mit Admin-Rechten gestartet und die SW ruft dann in festgelegten Zeiträumen das Updateprogramm auf. Das passiert normalerweise nach einer Update-Installation via CD beim ersten Programmstart.

Und nun das eigentliche Problem: Die Firewall blockiert das Updateprogramm natürlich bei der Erstinstallation und nach jeder Aktualisierung. Wir wissen ja, was User alles weg klicken, oder wohin sie "nicht" klicken, wenn sie sollen. Stichwort "Ach ja, die Meldung kommt immer..:"

Der Gedanke ist also, wenn ich bei der Installation die Lizenz abfrage (da passen die User noch richtig auf, weil sie die Lizenz ja installieren wollen/müssen) und anschließend herunterlade, dann habe ich ja zu dem Zeitpunkt schon eine aktive Verbindung und könnte doch in der Zeit wo ich die SW installiere, parallel dazu eventuell vorhandene Updates herunterladen.

- Das sollte ein eigener Thread sein, damit die Installation ungehindert fortgesetzt wird
- Das Installationsprogramm muss den Fortschritt des Downloadvorganges abfragen können.
- Wenn die Installation fertig und der Download noch nicht abgeschlossen ist, sollte auch der Downloadfortschritt angezeigt werden können
- Der Code sollte so "verpackt" sein, dass er auch vom eigentlichen Updateprogramm verwendet werden kann. Im Updateprogramm sind getrennt: Form (das was der User sieht), Logik (der Downloadvorgang, das Ersetzen der vorhandenen Dateien) in einer Unit, und der Datenbankzugriff in einem Datenmodul.

Nun habe ich über Threads schon einiges gelesen, so richtig kapiert hab ich das allerdings noch nicht. Noch dazu gibt's ja - wenn man sich die Beiträge hier so ansieht - auch sehr unterschiedliche und differenzierte Meinungen und Ansichten, wie man Threads einsetzt bzw. damit umgeht. Das macht es für mich nicht einfacher.

Ich bin Autodidakt, kein studierter Informatiker. Damit ich aber bei Problemen reagieren kann, muss ich das Ganze auch "verstehen" können. Darum meine Frage und Bitte nach Vorschlägen und Anregungen. Gerne gegen Bezahlung....in dem Fall bitte PN.

Mavarik 18. Dez 2014 12:33

AW: Update-Vorgang in einen Thread auslagern
 
Nicht das ich hier jemandem den Job wegnehmen will, aber Bezahlung wird nicht nötig sein.

Ob Du einen Download aufrufst und warten musst oder es in einen Thread auslagerst ist "erst mal" das Gleiche.

Mit zwei unterschieden:
1. Deine Application läuft mit anderen aufgaben weiter.
2. Du musst in Deiner Download-Procedure Zugriffe auf ein Form oder die VCL syncronisieren. (Bedeutet mit Syncronize eine Procedure aufrufen, die z.B. eine Processbar updatet)

Die eigentliche Frage lauten: An welcher Stelle kommst Du nicht weiter?

Mavarik

mm1256 18. Dez 2014 13:42

AW: Update-Vorgang in einen Thread auslagern
 
Hallo,

genauso einfach hab ich mir das ja vorgestellt...

Delphi-Quellcode:
unit uUpdateThread;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type

  TMyUpdateThread = class(TThread)
  protected
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    FMyUpdateThread: TMyUpdateThread;
    function UpdateStart: boolean;
  end;

var
  Form1: TForm1;

implementation

uses Dat_Glo, // Globales Datenmodul
     Update_Server; // Update-Form

{$R *.dfm}

procedure Execute_INTERACTIVE; // Schnittstelle zur Update-Form in Update_Server.pas
begin
  Application.CreateForm(TFrmUpdate_Server, FrmUpdate_Server); // Update-Form
  FrmUpdate_Server.Execute; // Update durchführen
end;


procedure TMyUpdateThread.Execute;
begin
  Execute_INTERACTIVE;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  UpdateStart;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyUpdateThread := nil;
end;

function TForm1.UpdateStart: boolean;
begin
  Result := true;
  FMyUpdateThread := TMyUpdateThread.Create(True);
  try
    FMyUpdateThread.FreeOnTerminate := True; // Gibt sich selber frei
    FMyUpdateThread.Resume; // Start
  except
    on E:Exception do begin
      Result := false;
      ShowMessage(E.Message);
    end;
  end;
end;

end.
Und jetzt scheitert es an der Synchronisierung. Also wie bekomme ich mit, wie weit der Download gerade ist (der Stand des Progressbar in FrmUpdate_Server)

Außerdem ist mir nicht klar, wann der Thread "vollkommen" fertig ist, damit ich FrmUpdate_Server wieder freigeben kann.

Mavarik 18. Dez 2014 13:47

AW: Update-Vorgang in einen Thread auslagern
 
OK! Erst mal in einem Thread kein FormCreate!

Der eigentlich download muss in den Thread...
Es gibt ein nettes Beispiel für Anonyme Threads.
Das Beispiel zeigt Dir auch direkt den Sync-Aufruf für Process & Ende...

Mavarik

mm1256 18. Dez 2014 14:29

AW: Update-Vorgang in einen Thread auslagern
 
Hallo,

erst mal vielen Dank für deine Bemühungen. Anonymer Thread bedeutet doch, dass die darin erstellten Objekte nicht geshared werden? Hmmmm....bedeutet das, dass ich dann außerhalb des Threads auf die Eigenschaften der Form zugreifen kann, also beispielsweise den Status des Progressbar abfragen? Weil ich die Form ja auch außerhalb des Thread erstellt habe. Das wäre ja einfach, dann müsste ich nur noch ein paar properties einbauen. Aber dann muss doch der Thread irgendwie die Form aktualisieren...oder stehe ich jetzt total auf dem Schlauch.

Hast du mal bitte einen Link auf das obengenannte Beispiel? Hier habe ich unter "Anonyme Threads" nichts prickelndes gefunden.

Sir Rufo 18. Dez 2014 15:59

AW: Update-Vorgang in einen Thread auslagern
 
[OT]
Auch wenn du es nicht hören willst, ich sage es trotzdem (nicht das nachher noch jemand sagt, warum das keiner gesagt hat, und ich mir dann denke, warum hast du das denn nicht einfach gesagt ...):

Wenn du den Krams umstellst auf
  • Kommunikation per HTTP(S) (löst die Firewall-Problematik)
  • Setup-Programm mit InnoSetup (oder wer auch immer) (löst die Nachlade-Problematik)
dann hast du diese ganzen Probleme nicht mehr und du beschreitest alte, bewährte und funktionierende Trampelpfade.

Aber du möchtest es ja nicht hören ... :stupid:
[/OT]

QuickAndDirty 18. Dez 2014 16:45

AW: Update-Vorgang in einen Thread auslagern
 
Ich habe Threads zuletzt immer über
TMultiReadExclusiveWriteSynchronizer oder TCriticalSection synchronisiert.

Um Nachrichten zwischen zwei Threads auszutauschen kann mann sich z.B.
ein Daten-Objekt bauen und dies in einer CriticalSection übergeben.
Sowohl Lesen als auch schreiben muss dann in einer CriticalSection in beiden Threads geschehen.
Oft macht es Sinn nicht einfach nur einzelnen Eigenschaften des Daten-Objects zu lesen sondern,
statt dessen mit einer Kopie zu arbeiten.
Denn die Kopie muss nicht in einer CriticalSection gefasst werden.

Wenn man nicht mit Kopien arbeiten will nur um das Datenobjekt von verschiedenen Threads auslesen zu lassen kann man
TMultiReadExclusiveWriteSynchronizer
Verwenden.
Der Blockt das lesen nur dann wenn gerade geschrieben wird. BZW.blockt das schreiben bis das Lesen beendet wurde.
Dieses Verfahren ist in Versorger/Verbraucher Konstellationen brauchbar.


Wenn Threads hauptsächlich "Warte"
Kommt man mit TEvent und und WaitForSingleObject oder WaitForMultipleObjects weiter
je nach dem ob man auf ein Event oder auf mehrere wartet.

mm1256 18. Dez 2014 16:56

AW: Update-Vorgang in einen Thread auslagern
 
Zitat:

Zitat von Sir Rufo (Beitrag 1283986)
Aber du möchtest es ja nicht hören ...

Nein, der Eindruck täuscht, das stimmt so wirklich nicht. Wenn ich so beratungsresistent wäre, dann würde ich (respektive meine SW bzw. Firma) anders da stehen. Die Frage ist doch anders herum die, warum ich meine eigene Installationsroutine verwende, und nicht Inno oder Installshield oder....sonst was. Das hatte ich schon. Bin damit auch glücklich gewesen, bis ich an den Punkt kam, wo es nicht mehr weiter ging. Wo diese Installationsprogramme einfach versagten, wo ich zwar Erweiterungen Plugins usw. in die Installation einbauen kann, um spezielle Aufgaben zu erledigen, aber dann kann ich den Rest auch gleich erledigen. Da geht es um mehr als nur eine SW zu installieren und sie über's WEB upzudaten.

Ich möchte dich/euch damit nicht langweilen, aber was da (an dem Installationsprogramm) alles dran hängt, das ist mit keinem Standard-Tool wie Inno & Co lösbar. Wenn es dich/euch interessiert, dann bin ich sehr gerne bereit mal einen Einblick geben, was da alles drin und dran steckt. Dann machen wir woanders (beispielsweise unter "Sonstige Werkzeuge") einen neuen Thread dafür auf.

Weil das aber nicht Bestandteil meines Problems ist, wollte ich "alternative Vorschläge" vermeiden. Diese führen in der Regel zu Diskussionen die in der Sache selber nicht weiterbringen. Dafür gibt es hier und in nahezu jedem größeren Internetforum endlose Beispiele.

Sir Rufo 18. Dez 2014 17:06

AW: Update-Vorgang in einen Thread auslagern
 
Möglicherweise bist du nicht beratungsresistent, aber dir fehlt es gerade an Fantasie ;)

Mit InnoSetup kann ich mir wunderbar etwas zusammenbauen, was mir aus dem Internet etwas lädt und installiert/ausführt. Ist das auf bestimmte Sachen beschränkt? Nö, muss ja nur etwas ausführbares sein. Also ich könnte mein eigenes Installationsprogramm laden/nachladen wenn nicht aktuell und ausführen. Ja, das ist möglich.

Did you get the point?

mm1256 18. Dez 2014 17:14

AW: Update-Vorgang in einen Thread auslagern
 
Hallo Andreas,

was du ansprichst sind genau die Dinge, von denen ich zu wenig bis gar keine Ahnung bzw. Praxis habe. Das Installationsprogramm benutzt Units die globale Ressourcen bereitstellen, z.B. die Registry-Einträge die in einem Rutsch beim Programmstart eingelesen werden, und wenn das Programm geschlossen wird, wieder in einem Rutsch zurück geschrieben werden. Das minimiert Registry-Zugriffe. Das Updateprogramm greift auch auf diese globalen Strukturen zu. Also müsste man da "vermutlich" mit Critical Sections arbeiten. Da das aber insgesamt über einen Zeitraum von mehreren Minuten gehen kann, und Critical Sections eher kurz gehalten werden sollen, wird es wieder (zumindest für mich) komplizierter bzw. komplexer, als es auf Anhieb aussieht.

Darum war der ursprüngliche Ansatz (siehe Code) der, dass ich die ganze Form und deren Routinen in den Thread hinein packe. Was ich aber lt. Mavarik nicht tun sollte.

Mich beschleicht langsam der Gedanke, dass ich mit einer separaten DLL, deren update-ausführende Routine ich in einem Thread lade, dem Ziel näher komme. Dann habe ich zwar keine Synchronisation, aber weniger (Speicher-)Probleme, und ich weiß am Ende der Installation auch, ob der Download läuft oder nicht. Wäre das nicht eine Alternative?

@Sir Rufo
Zitat:

Möglicherweise bist du nicht beratungsresistent, aber dir fehlt es gerade an Fantasie
Na gut, dann habe ich also keine Fantasie. Damit kann ich leben, und du darfst weiterhin mit Inno glücklich sein. Was wollen wir denn mehr?


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:00 Uhr.
Seite 1 von 4  1 23     Letzte »    

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