![]() |
Delphi-Version: 5
DLL und Threads
Hallo alle...:hi:
...schöne Ostern wünsch ich. 8-) Zur Frage: Bekannt ist ja, daß eine DLL nur einmal je Prozeß geladen wird. Meine DLL exportiert eine Hand voll Prozeduren. Diese Prozeduren wiederum werden in verschiedenen parallel laufenden Threads verwendet. Was ist zu beachten? Wo gehört LoadLibrary und FreeLibrary hin? Müssen die Threads synchronisiert auf die DLL Prozeduren zugreifen? Danke für Info´s. |
AW: DLL und Threads
Denk beim Multi-Threading immer an folgendes:
Ich kann problemlos zu n Personen sprechen und die gesprochenen Worte kommen dort an. Umgekehrt funktioniert das mit n>1 aber nicht. Sorge einfach dafür, dass dieser umgekehrte Fall nicht eintreten kann und dein Code ist threadsafe. |
AW: DLL und Threads
:( Dann ist mein Konzept für die Katz...
Hintergrund: Die DLL parst einen HTML Response. Dieser Response wird in verschiedenen paralelen Threads(HTML Anfragen) abgeholt und soll im Thread geparst und das Ergebnis gespeichert werden. Wenn ich pro Thread die gleiche DLL laden könnte... Das soll ja mit Tricks glaube ich funktionieren. Ich guck mal... Tipps sind willkommen. :P |
AW: DLL und Threads
Ohne jetzt großartig nachgedacht zu haben: was ist denn, wenn die DLL die Threads erzeugt? Mit CallBack-Parametern beim Aufruf müsste das doch funktionieren, oder?
|
AW: DLL und Threads
Du meinst innerhalb der DLL im Speicherkontext der DLL?
Hmmm... Denke ich mal drüber nach. :roll: Der Thread hat ja die "Lade Schleife" als Aufgabe. Das hat eigentlich in der DLL nix verloren. Die soll ausschließlich den Response parsen und die jeweiligen "Connection Strings" für die Anfrage vorhalten. |
AW: DLL und Threads
Streich mal das DLL Geraffel aus deinen Überlegungen, denn in der DLL ist einfach nur Code ausgelagert.
Ob eine DLL threadsafe ist, hängt nicht davon ab, ob der Code in einer DLL ist, sondern ob der Code threadsafe ist. Also kann man das aus der Überlegung auch rausnehmen. Ich baue mal eben eine kleine Demo, um das zu veranschaulichen ... dauert einen kleinen Moment. |
AW: DLL und Threads
Zitat:
Nachtrag: Im Prinzip funktioniert das auch. Ich bin auf die Suche gegangen weil die eine Funktion aus der DLL exakt 13 mal den Text korrekt parst und beim 14 mal mit einer Zugriffsverletzung in der DLL abschmiert. Deswegen dachte ich an einen Grundsatzfehler. Diese:
Delphi-Quellcode:
Aufgerufen hier: (FParser ist das Objekt welches sich um das Laden der DLL kümmert und die exportierten Geschichten zur Verfügung stellt)
procedure ParseDeviceParameters(const aText: PChar; Parameters: TDeviceParameterList); stdcall;
var aParameter: TDeviceParameter; I, PositionFirst, PositionCount, TempPosition: Integer; sl: TStringList; begin sl:= TStringList.Create; try sl.Text:= aText; for I:= 0 to sl.Count - 1 do begin if AnsiStartsText('dvcRec[', sl[I]) then begin aParameter:= TDeviceParameter.Create; PositionFirst:= PosEx('(',sl[I],1) + 1; PositionCount:= PosEx(',',sl[I],PositionFirst) - PositionFirst; aParameter.ParameterID:= StrToInt(Copy(sl[I],PositionFirst,PositionCount)); PositionFirst:= PosEx('"',sl[I],1) + 1; TempPosition:= PositionFirst; PositionCount:= PosEx('"',sl[I],TempPosition) - PositionFirst; aParameter.Name:= Copy(sl[I],PositionFirst,PositionCount); TempPosition:= TempPosition + PositionCount + 1; PositionFirst:= PosEx(',',sl[I],TempPosition) + 1; PositionCount:= PosEx(',',sl[I],PositionFirst) - PositionFirst; aParameter.GroupID:= StrToInt(Copy(sl[I],PositionFirst,PositionCount)); TempPosition:= TempPosition + PositionCount + 2; PositionFirst:= PosEx('"',sl[I],TempPosition) + 1; PositionCount:= PosEx('"',sl[I],PositionFirst) - PositionFirst; aParameter.Measure:= Copy(sl[I],PositionFirst,PositionCount); if aParameter.Measure = ' ' then begin aParameter.ParameterType:= ptDigital; end else begin aParameter.ParameterType:= ptAnalog; end; aParameter.State:= dsLoaded; Parameters.Add(aParameter); end; end; finally sl.Free; end; end;
Delphi-Quellcode:
FParser.ParseDeviceParameters(PChar(FResponseText), FDeviceParameterList);
for DeviceParameter in FDeviceParameterList do begin DeviceParameter.DeviceID := FCurrentDevice.ID; end; FDatabase.SaveList(FDeviceParameterList); FDatabase.GetList(FDeviceParameterList, FCurrentDevice); Zitat:
|
AW: DLL und Threads
Parser-Interface:
Delphi-Quellcode:
und ein simpler nicht threadsafe Parser:
unit Parser;
interface type IParser = interface ['{7082CCBB-2680-4BC4-8B17-7FFE1D602A0A}'] function Parse( const AString : string ) : TArray<string>; end; implementation end.
Delphi-Quellcode:
den ich einfach wrappe um mit dem doch threadsafe arbeiten zu können
unit SimpleParser;
interface uses Classes, Parser; type TParserState = procedure( AChar : Char ) of object; TSimpleParser = class( TInterfacedObject, IParser ) private FState : TParserState; FBuffer : string; FTokens : TStrings; procedure StartState( AChar : Char ); procedure TokenState( AChar : Char ); public constructor Create; destructor Destroy; override; function Parse( const AString : string ) : TArray<string>; end; implementation { TSimpleParser } constructor TSimpleParser.Create; begin inherited; FTokens := TStringList.Create; end; destructor TSimpleParser.Destroy; begin FTokens.Free; inherited; end; function TSimpleParser.Parse( const AString : string ) : TArray<string>; var LIdx : Integer; begin FTokens.Clear; FState := StartState; for LIdx := 1 to Length( AString ) do begin FState( AString[LIdx] ); end; Result := FTokens.ToStringArray; end; procedure TSimpleParser.StartState( AChar : Char ); begin case AChar of ' ' : ; ',' : ; else FState := TokenState; FState(AChar); end; end; procedure TSimpleParser.TokenState( AChar : Char ); begin case AChar of ',' : begin FTokens.Add( FBuffer ); FBuffer := ''; FState := StartState; end; else FBuffer := FBuffer + AChar; end; end; end.
Delphi-Quellcode:
unit ThreadSafeParser;
interface uses Parser; type TThreadSafeParser = class( TInterfacedObject, IParser ) public function Parse( const AString : string ) : TArray<string>; end; implementation uses SimpleParser; { TThreadSafeParser } function TThreadSafeParser.Parse( const AString : string ) : TArray<string>; var LParser : IParser; begin // TSimpleParser ist nicht threadsafe, aber // hier wird bei jedem Aufruf eine eigene Instanz erzeugt, auf die niemand sonst zugreift // dadurch wird das jetzt threadsafe LParser := TSimpleParser.Create; Result := LParser.Parse( AString ); end; end.
Delphi-Quellcode:
procedure Test;
var LParser : IParser; begin LParser := TSimpleParser.Create; OutputParseResult( LParser.Parse( '1,2,3,4' ) ); LParser := TThreadSafeParser.Create; OutputParseResult( LParser.Parse( '1,2,3,4' ) ); end; |
AW: DLL und Threads
Zitat:
Delphi-Quellcode:
,
FParser
Delphi-Quellcode:
auch insgesamt threadsafe?
FDatabase
|
AW: DLL und Threads
FParser und FDatabase sind jeweils im Create des Threads erzeugt und im Destroy freigegeben. Da sollte das gut sein... :zwinker: Der Thread soll völlig allein die Aufgabe abarbeiten (incl. Datenbankspeicherung). Der Parser hat zwar seine eigene Instanz im Thread aber dann das gleiche DLL Handle wie der nächste bzw. vorhergehende Thread.
Wenn ich die o.g. Funktion auskommentiere läuft das ganze und beendet sich ohne Speicherlöcher und Zugriffverletzungen. Nehme ich sie rein ist bei 13 Schluß. An dem HTML Response ist nix außergewöhnliches zu erkennen. PS: Ich hatte auch schon an ein Interface gedacht Die DLL gibt ein Interface zurück und es wird nur mit dem Interface gearbeitet statt mit den Funktionen. Macht das einen Unterschied mit dem DLL Handling? Warum DLL: Es gibt geschätzt 30 verschiedene Geräteversionen die sich im Response unterscheiden. Die passende DLL (Parser) zur Geräteversion wird dynamisch geladen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:09 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