AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten
Thema durchsuchen
Ansicht
Themen-Optionen

HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

Ein Thema von Markus Effenberger · begonnen am 19. Apr 2019 · letzter Beitrag vom 20. Apr 2019
Antwort Antwort
Markus Effenberger

Registriert seit: 2. Jul 2014
44 Beiträge
 
Delphi 10.3 Rio
 
#1

HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 18:54
Hallo,

Das Problem wurde leider immer noch nicht gelöst

Es wird ein IdHTTPServer betrieben.
Im OnGet kommen z.B. Bestellungen rein, die z.B. einen Bondruck mittels FastReport anstoßen.
Weil sich der Fastreport aktuell auf einem Form der GUI befindet, darf immer nur ein OnGet einzeln abgearbeitet werden.
Also alle OnGet-Ereignisse (insbesondere die Funktion ANTWORTEN_ERZEUGEN) sollen NACHEINANDER abgearbeitet werden.
Wenn ein OnGet durch eine Anfrage ausgelöst wird, und gerade schon ein anderer Thread die Funktion ANTWORTEN_ERZEUGEN abarbeitet, dann soll der neue OnGet-Thread VOR ANTWORTEN_ERZEUGEN warten und die Funktion ANTWORTEN_ERZEUGEN erst beginnen, wenn die Funktion in dem anderen Thread VOLLSTÄNDIG abgearbeitet ist.
Untenstehend ist der Code zu sehen, mit dem ich das versucht habe. Aber es funktioniert irgendwie nicht.
Mein Eindruck ist, dass ein Thread aus der Funktion ANTWORTEN_ERZEUGEN rausspringt bzw fertig ist, obwohl der Druck und/oder die Abarbeitung (z.B. Filtern von Tables und Schleifen durch die Tables) gerade noch stattfindet.

Hat jemand zufällig einen Vorschlag, wie man das Problem lösen kann? Mir gehen allmählich die Ideen aus. Falls das eine Rolle spielt: Es wird Firemonkey genutzt.

Die Ausgaben "Deadlock detected" und "DoubleGet detected" erscheinen ab und zu beide. Wenn ein Client ab und zu mal ein paar Sekunden warten muss wegen der seriellen Abarbeitung wäre das nicht weiter schlimm.

Markus


Code:
procedure TfrmMain.HTTPServerCommandGet(AContext: TIdContext;
                                        ARequestInfo: TIdHTTPRequestInfo;
                                        AResponseInfo: TIdHTTPResponseInfo);
begin

  try


    GUI_Lock_Starten_oder_Warten;
    TThread.Synchronize(nil,
       procedure
       begin
         ANTWORTEN_ERZEUGEN(AContext, ARequestInfo, AResponseInfo); // -> AResponseInfo.ContentText
       end
    );
    GUI_Lock_Aufheben;

  except
    on e:exception do
      begin
        AResponseInfo.ContentText := 'Systemfehlermeldung vom Server: ' + e.Message;
      end;
  end;

end;

procedure TfrmMain.GUI_Lock_Starten_oder_Warten;
var SperreAktiv : Boolean;
    warten : integer;
begin

  try

    SperreAktiv := True;
    while SperreAktiv do
      begin

        try
          if not HTTP_is_working
            then begin
              SperreAktiv := False;
            end else begin
              try
                ButtonDeadlock2.Text := 'DoubleGet detected at ' + DateTimeToStr(Now);
              except
                on exception do begin end;
              end;
            end;
        except
          on e:exception do begin end;
        end;
        warten := RandomRange(150,300);
        Sleep(warten);

      end; // while

    HTTP_is_working := True;
    HTTP_is_working_last_Start := Now;

  except
    on e:exception do begin end;
  end;

end;

procedure TfrmMain.GUI_Lock_Aufheben;
begin
  try
    HTTP_is_working := False;
  except
    on e:exception do begin end;
  end;
end;

procedure TfrmMain.Timer_HTTP_Deadlock_Timeout_prüfenTimer(Sender: TObject);
begin

  try

    if HTTP_is_working then
      begin

        if (Abs(SecondsBetween(HTTP_is_working_last_Start,Now)) > 7)
          then begin
            HTTP_is_working := False; // Deadlock übergehen
            try
              ButtonDeadlock.Text := 'Deadlock detected at ' + DateTimeToStr(Now);
            except
              on e:exception do begin end;
            end;
          end;

      end;

  except
    on e:exception do begin end;
  end;

end;

Geändert von Markus Effenberger (19. Apr 2019 um 19:01 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von FaTaLGuiLLoTiNe
FaTaLGuiLLoTiNe

Registriert seit: 3. Jul 2004
Ort: NRW
55 Beiträge
 
Delphi XE Enterprise
 
#2

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 19:04
Du könntest dir mal TCriticalSection ansehen.
Christian
<< FaTaLGuiLLoTiNe >>
Rhinoceroses don't play games!
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
970 Beiträge
 
Delphi 6 Professional
 
#3

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 19:19
Hmm..

Meines Wissens ist jeder Aufruf von HTTPServerCommandGet bereits ein eigener Thread..

Für das Problem mit Warten, bis anderer Thread fertig empfehle ich mal so: TCriticalSection

Eine CriticalSection global in deinem HTTP-Server erzeugen und dann in jedem HTTPServerCommandGet:

(Nur so herunter getippt..)

Delphi-Quellcode:
var
  CS : TCriticalSection; // z.B. im initialization erstellt...

procedure TfrmMain.HTTPServerCommandGet(AContext: TIdContext;
                                        ARequestInfo: TIdHTTPRequestInfo;
                                        AResponseInfo: TIdHTTPResponseInfo);
begin
  CS.Acquire;
  try

    ANTWORTEN_ERZEUGEN(AContext, ARequestInfo, AResponseInfo);

  finally
    CS.Release;
  end;
end;
So führt der erste Thread das ANTWORTEN_ERZEUGEN aus und alle anderen warten (durch Acquire) bis er fertig ist.
Wenn diese fertig ist (Release), kommt der nächste dran....

Durch die Globale Verwendung ist zu mindestens der gleichzeitige Zugriff aus den Threads auf ANTWORTEN_ERZEUGEN verhindert..
Jedoch dürfte es hier noch Probleme mit HauptThread geben, da wir ja immer noch der (nicht über TCriticalSection) erzeugten und vom Formular verwendeten Report haben.

Somit würde ich diesen nicht auf dem Formular platzieren, sondern davon losgelöst in einem eigenen Thread, der auch nur per globaler CriticalSection darauf zugreift...
  Mit Zitat antworten Zitat
Markus Effenberger

Registriert seit: 2. Jul 2014
44 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 20:34
Hmm..

...
Eine CriticalSection global in deinem HTTP-Server erzeugen und dann in jedem HTTPServerCommandGet:

(Nur so herunter getippt..)
Ich hatte zuvor schonmal versucht, das Ganze mit einer CriticalSection zu lösen, aber das hatte leider auch keinen Erfolg. Aber vielleicht lohnt es sich ja mal, die CriticalSection mit der Synchronize-Kapselung zu kombinieren. Ich habe mich diesbezüglich jetzt nochmal in das Thema CS reingelesen und habe jetzt noch eine Verständnisfrage.

Hat jemand genauere Informationen über den Unterschied zwischen "Enter" und "Acquire"?

"Acquire attempts to enter the critical section. It will suspend the calling thread if the critical section is in use by another thread, and will resume as soon as the other thread has released the critical section."

"Call Enter to block all other threads from entering code protected by this critical section until the Leave or Release method is called. Enter calls the Acquire method to bind the critical section to the calling thread."

Da steht also quasi mit "Acquire" wartet man.
Mit "Enter" blockt man und ruft das Warten auf.
Was genau macht es dann für einen Sinn, "nur" Acquire aufzurufen?


Markus
  Mit Zitat antworten Zitat
Klaus01
Online

Registriert seit: 30. Nov 2005
Ort: München
5.768 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 21:01
..vielleicht bringt dieser Thread etwas Erleuchtung: https://www.delphipraxis.net/178723-...-vs-enter.html

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Markus Effenberger

Registriert seit: 2. Jul 2014
44 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 19. Apr 2019, 21:20
..vielleicht bringt dieser Thread etwas Erleuchtung: https://www.delphipraxis.net/178723-...-vs-enter.html
In der Tat. Danke!
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
741 Beiträge
 
#7

AW: HTTP-Get-Thread NIEMALS zwei gleichzeitig abarbeiten

  Alt 20. Apr 2019, 13:35
Hier sind ein paar Einstellungen zu sehen, die wichtig sein könnten; insbesondere "Report.EngineOptions.EnableThreadSafe := True;" und "Report.EngineOptions.UseGlobalDataSetList := False;" denke ich.

Wenn du die Komponenten auf ein DataModule setzt und pro Thread eine Instanz davon erstellst, könntest du auch unabhängig drucken.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 Uhr.
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