AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Thread in DLL richtig freigeben

Ein Thema von Dalai · begonnen am 4. Jun 2022 · letzter Beitrag vom 6. Jun 2022
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#1

Thread in DLL richtig freigeben

  Alt 4. Jun 2022, 19:04
Hallo Leute, ich benötige mal wieder euer Fachwissen. Basierend auf Sir Rufos Vorschlag hab ich einen Thread zusammengebaut. Nachfolgend die nach Tests sehr stark abgespeckte Variante.
Delphi-Quellcode:
type
  TSignatureVerificationThread2 = class(TThread)
  private
    FCS: TCriticalSection;
    FEvent: TEvent;
    FWorkList: TObjectList;
    function GetItem: TObject;
  protected
    procedure Execute; override;
    {$IFDEF USE_TERMINATEDSET}
    procedure TerminatedSet; override;
    {$ENDIF USE_TERMINATEDSET}
  public
    constructor Create;
    destructor Destroy; override;
    procedure WorkOnItem(const AItem: TObject);
  end;

implementation

{ TSignatureVerificationThread2 }

constructor TSignatureVerificationThread2.Create;
begin
// FreeOnTerminate:= True;
    FCS:= TCriticalSection.Create;
    FEvent:= TEvent.Create(nil, False, False, '');
    FWorkList:= TObjectList.Create(True);
    inherited Create(False);
end;

destructor TSignatureVerificationThread2.Destroy;
begin
{$IFDEF USE_TERMINATEDSET}
{$ELSE}
    Terminate;
    FEvent.SetEvent;
{$ENDIF USE_TERMINATEDSET}
    inherited;
    FWorkList.Free;
    FEvent.Free;
    FCS.Free;
end;

{$IFDEF USE_TERMINATEDSET}
procedure TSignatureVerificationThread2.TerminatedSet;
begin
    inherited;
    FEvent.SetEvent;
end;
{$ENDIF USE_TERMINATEDSET}

function TSignatureVerificationThread2.GetItem: TObject;
begin
    FCS.Enter;
    try
        Result:= FWorkList.Extract(FWorkList.First);
        if (FWorkList.Count > 0) then
            FEvent.SetEvent;
    finally
        FCS.Leave;
    end;
end;

procedure TSignatureVerificationThread2.Execute;
begin
    while NOT Terminated do begin
        FEvent.WaitFor(INFINITE);
        if NOT Terminated then begin
        end;
    end;
end;

procedure TSignatureVerificationThread2.WorkOnItem(const AItem: TObject);
begin
   FCS.Enter;
   try
       FWorkList.Add(AItem);
       FEvent.SetEvent;
   finally
       FCS.Leave;
   end;
end;
Delphi-Quellcode:
library FooBar;

{$IFDEF VERIFY_IN_BACKGROUND_THREAD}
var Glob_SigThread: TSignatureVerificationThread2;
    {$ENDIF VERIFY_IN_BACKGROUND_THREAD}

[...]

procedure DllEntryPoint(dwReason: DWORD);
begin
[...]
DLL_PROCESS_DETACH:
            begin
              {$IFDEF VERIFY_IN_BACKGROUND_THREAD}
              if Assigned(Glob_SigThread) then begin
                  Glob_SigThread.Terminate;
// Glob_SigThread.WaitFor;
              end;
              FreeAndNil(Glob_SigThread);
              {$ENDIF VERIFY_IN_BACKGROUND_THREAD}
           end;
[...]
end;
Der hier gezeigte Thread macht ja eigentlich gar nichts, und trotzdem ist die Freigabe absolut unzuverlässig. Manchmal klappt es sauber, aber meist hängt die ganze Sache im Destruktor des Threads, konkret beim vererbten WaitFor, und lastet dabei einen Kern voll aus. Nun habe ich an mehreren Stellen im Internet gelesen, dass die Stelle DLL_PROCESS_DETACH zum Freigeben des Threads ungünstig bzw. zu spät ist. Kann mir jemand sagen, ob das zutrifft, und vielleicht noch eine Erklärung liefern, warum das so ist? Sind die Probleme also wirklich erwartbar?

Das Hostprogramm, in dem meine DLL geladen wird, stammt nicht von mir und ist als gegeben hinzunehmen. Es gibt im DLL-Interface des Hostprogramms keine Funktion, die vor dem Entladen der DLL gerufen werden könnte. Sollte das Freigeben an dieser Stelle tatsächlich ein Problem sein, weiß ich nicht so recht, wie es anders gehen sollte. Hat dazu jemand noch eine Idee?

Grüße
Dalai
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
702 Beiträge
 
Delphi 12 Athens
 
#2

AW: Thread in DLL richtig freigeben

  Alt 5. Jun 2022, 10:56
Falls die DLL erst beim Ende des Programms entladen wird würde ich den Thread einfach vergessen. Wozu das Objekt freigeben wenn der Memory manager eh im Begriff ist, ins Nirwana einzugehen? Und Windows ist mittlerweile wirklich gut darin, bei Programmende alle vom Programm verwendeten Resourcen (alle Arten von handles, eingeschlossen die von Threads) aufzuräumen.

Was Du auf keinen Fall machen darfst ist an diesem Punkt auf das Ende des Threads zu warten, sowas ist so ziemlich die einzige Ursache dafür, das ein Prozess nicht vollständig beendet wird (noch im Task Manager gelistet ist, nachdem sein UI geschlossen wurde).

Manchmal ist es sinnvoller, pragmatisch anstelle von penibel zu sein.
Peter Below
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#3

AW: Thread in DLL richtig freigeben

  Alt 5. Jun 2022, 21:39
Wegen der in Teilen unvollständigen Dokumentation der DLL-Schnittstelle war ich davon ausgegangen, es gäbe keine Funktion, die das Hostprogramm vor dem Entladen der DLL ruft. Nun stellte sich heraus, dass es doch eine solche gibt. Ich hatte die vorher komplett übersehen, weil sie im Delphi-Beispiel der Doku einfach fehlt.

Nachdem ich die Freigabe des Threads dorthin verschoben habe, klappt alles wie erwartet. Ich muss also nicht das OS hinter meiner DLL herräumen lassen.

Sollten sich wider Erwarten Probleme ergeben, werd ich mich nochmal melden. Unabhängig davon danke ich allen Beteiligten und Lesern fürs Mitdenken und sage sorry für den falschen Alarm. Nichtsdestotrotz würde mich interessieren, ob es wirklich eine gute Idee ist, im Fall des Falles dem OS das Aufräumen zu überlassen, oder ob es nicht einen besseren Weg gibt.

Grüße
Dalai
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#4

AW: Thread in DLL richtig freigeben

  Alt 5. Jun 2022, 23:53
Man kann auch Finalization einer Unit oder den Class Destructor einer Klasse verwenden, um auf das Entladen einer DLL oder ordnungsgemäßes Beenden einer EXE zu reagieren.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.942 Beiträge
 
Delphi 12 Athens
 
#5

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 09:40
Wegen der in Teilen unvollständigen Dokumentation der DLL-Schnittstelle war ich davon ausgegangen, es gäbe keine Funktion, die das Hostprogramm vor dem Entladen der DLL ruft. Nun stellte sich heraus, dass es doch eine solche gibt. Ich hatte die vorher komplett übersehen, weil sie im Delphi-Beispiel der Doku einfach fehlt.

Nachdem ich die Freigabe des Threads dorthin verschoben habe, klappt alles wie erwartet. Ich muss also nicht das OS hinter meiner DLL herräumen lassen.

Sollten sich wider Erwarten Probleme ergeben, werd ich mich nochmal melden. Unabhängig davon danke ich allen Beteiligten und Lesern fürs Mitdenken und sage sorry für den falschen Alarm. Nichtsdestotrotz würde mich interessieren, ob es wirklich eine gute Idee ist, im Fall des Falles dem OS das Aufräumen zu überlassen, oder ob es nicht einen besseren Weg gibt.

Grüße
Dalai
Magst du uns mitteilen, welche FUnktion da automatisch aufgerufen wird?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#6

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 13:30
vielleicht
Bei Google suchenDelphi DllEntryPoint
Bei Google suchenDelphi DllMain

oder das Programm, welches die DLL einbindet, ruft selber eine Init-Prozedur auf. (wie z.B. bei PluginSystem gern gemacht)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#7

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 14:50
@himitsu:
Von DllEntryPoint hab ich ja bereits im OP einen Auszug in Codeform gepostet. Und es geht auch nicht um Init-Funktionen sondern deren Pendant vor dem Entladen der DLL.

@TurboMagic:
Dachte nicht, dass das relevant ist. Meine Ausführungen hatte ich recht allgemein gehalten, weil die Problematik sich ja immer dort stellt, wo DLLs Threads erzeugen und vor deren Entladen wieder freigeben sollen. Anyway, die nun gefundene Funktion heißt FsContentPluginUnloading und stammt vom WFX-Plugin-Interface von Total Commander. Offenbar ruft TC diese Funktion, bevor er mit FreeLibrary ein Plugin entlädt - aber natürlich nur, wenn ein Plugin diese Funktion exportiert.

Grüße
Dalai
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#8

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 15:18
Der DllEntryPoint/DllMain wird beim Laden und Entladen aufgerufen.

Beim Laden hat man es indirekt ... der BEGIN-END-Block in der DPR.
Für's Entladen muß man sich registrieren.

Oder man nimmt eben das, was man in den Units hat.
initialization und finalization
oder eben Class Constructor und Class Destructor


Der EntryPoint der EXE/DLL ist im Pascal "versteckt",
bzw. der ruft von innen aus nacheinander das BEGIN-END der DPR und alle Initialization/Finalization der Units auf.
Zuerst die Class-Constructor, dann Initialization, jeweils für alle Units und zum Schluß den Main-Code in der DPR.
Und beim Entladen genau andersrum. (nur eben normal ohne einen Code in der DPR, außer man überschreibt die MainProc)



Zitat:
FsContentPluginUnloading
Genau, es macht das Programm, welches solche DLLs lädt. (sowas findet man natürlich in der Dokumentation der API)
Vor allem, um beim Laden noch einige Werte zu übergeben, und/oder vorher noch paar Dinge zu initialisieren.

Ist das Gleiche, wie das "Register" im Delphi, für IDE-Plugins.
https://docwiki.embarcadero.com/RADS...nents_aufrufen
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 6. Jun 2022 um 15:28 Uhr)
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.942 Beiträge
 
Delphi 12 Athens
 
#9

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 15:58
Da ich nicht raten mag, hätt' ich gerne vom OP die Info, was ihm jetzt geholfen hat.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#10

AW: Thread in DLL richtig freigeben

  Alt 6. Jun 2022, 17:48
Es sollte nun klar sein, was geholfen hat. Der Vollständigkeit halber nochmal: Die Freigabe des Threads erfolgt nun in der zusätzlich implementierten und exportierten Funktion FsContentPluginUnloading statt im DllEntryPoint bei DLL_PROCESS_DETACH. Letzteres ist wirklich der zuletzt aufgerufene Code, und offensichtlich für eine Freigabe von Threads zu spät.

Grüße
Dalai
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 20:30 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