AGB  ·  Datenschutz  ·  Impressum  







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

DLL und Threads

Ein Thema von haentschman · begonnen am 18. Apr 2014 · letzter Beitrag vom 19. Apr 2014
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.303 Beiträge
 
Delphi 12 Athens
 
#1

AW: DLL und Threads

  Alt 18. Apr 2014, 11:56
Du meinst innerhalb der DLL im Speicherkontext der DLL?

Hmmm... Denke ich mal drüber nach.
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.

Geändert von haentschman (18. Apr 2014 um 11:59 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: DLL und Threads

  Alt 18. Apr 2014, 12:12
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.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.303 Beiträge
 
Delphi 12 Athens
 
#3

AW: DLL und Threads

  Alt 18. Apr 2014, 12:22
Zitat:
Streich mal das DLL Geraffel aus deinen Überlegungen, denn in der DLL ist einfach nur Code ausgelagert.
... ja klar. Und dieser Code sollte, so die Idee, in mehreren Threads aufrufbar sein.

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:
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;
Aufgerufen hier: (FParser ist das Objekt welches sich um das Laden der DLL kümmert und die exportierten Geschichten zur Verfügung stellt)
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:
Erste Gelegenheit für Exception bei $771AC41F. Exception-Klasse EAccessViolation mit Meldung 'Zugriffsverletzung bei Adresse 08D2328B in Modul 'BLA_500_V1_2.dll'. Schreiben von Adresse 00000001'. Prozess DVAServer.exe (3640)

Geändert von haentschman (18. Apr 2014 um 12:38 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: DLL und Threads

  Alt 18. Apr 2014, 12:51
Parser-Interface:
Delphi-Quellcode:
unit Parser;

interface

type
  IParser = interface
    ['{7082CCBB-2680-4BC4-8B17-7FFE1D602A0A}']
    function Parse( const AString : string ) : TArray<string>;
  end;

implementation

end.
und ein simpler nicht threadsafe Parser:
Delphi-Quellcode:
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.
den ich einfach wrappe um mit dem doch threadsafe arbeiten zu können
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;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (18. Apr 2014 um 12:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: DLL und Threads

  Alt 18. Apr 2014, 12:52
Aufgerufen hier: (FParser ist das Objekt welches sich um das Laden der DLL kümmert und die exportierten Geschichten zur Verfügung stellt)
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:
Erste Gelegenheit für Exception bei $771AC41F. Exception-Klasse EAccessViolation mit Meldung 'Zugriffsverletzung bei Adresse 08D2328B in Modul 'BLA_500_V1_2.dll'. Schreiben von Adresse 00000001'. Prozess DVAServer.exe (3640)
Ist der Zugriff auf FParser , FDatabase auch insgesamt threadsafe?
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.303 Beiträge
 
Delphi 12 Athens
 
#6

AW: DLL und Threads

  Alt 18. Apr 2014, 12:59
FParser und FDatabase sind jeweils im Create des Threads erzeugt und im Destroy freigegeben. Da sollte das gut sein... 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.

Geändert von haentschman (18. Apr 2014 um 13:03 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.545 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: DLL und Threads

  Alt 18. Apr 2014, 13:03
Zitat:
FParser.ParseDeviceParameters(PChar(FResponseText), FDeviceParameterList);
Wird der Code aus der Anwendung heraus ausgeführt oder nur innerhalb der DLL?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.303 Beiträge
 
Delphi 12 Athens
 
#8

AW: DLL und Threads

  Alt 18. Apr 2014, 13:12
.. nicht in der DLL nur im Thread. Der Thread soll die DLL benutzen.

DLL:
Delphi-Quellcode:
procedure ParseDeviceParameters(const aText: PChar; Parameters: TDeviceParameterList)
.
.
exports
  ParseDeviceParameters
.
.
TParser, instanziert im Thread:
Delphi-Quellcode:
FDLL: string;
FMasterDeviceDLLHandle: THandle;
procedure LoadDLL;
.
.
constructor TParser.Create(aDLL: string);
begin
  inherited Create;
  FMasterDeviceDLLHandle:= 0;
  FDLL:= aDLL;
  LoadDLL;
end;

procedure TParser.LoadDLL;
begin
  FMasterDeviceDllHandle:= LoadLibrary(PChar(FDLL));
  if FMasterDeviceDllHandle <> 0 then begin
    FParseDeviceParameters:= GetProcAddress(FMasterDeviceDllHandle, 'ParseDeviceParameters');
.
.
  end
  else
  begin
    raise Exception.Create('DLL ' + QuotedStr(FDLL) + ' konnte nicht geladen werden.');
  end;
end;

procedure TParser.ParseDeviceParameters(aText: PChar; ParameterList: TDeviceParameterList);
begin
  FParseDeviceParameters(aText, ParameterList);
end;
Aus dem Thread:
FParser.ParseDeviceParameters(PChar(FResponseText), FDeviceParameterList);

Geändert von haentschman (18. Apr 2014 um 13:14 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#9

AW: DLL und Threads

  Alt 18. Apr 2014, 13:15
Das "Warum DLL" spielt hier doch keine Rolle (persönlich würde ich das auch mit DLL's/Plugins machen).

Es kommt nur darauf an, wie du das in der DLL umgesetzt hast.

Als Beispiel nehme ich mal TSimpleParser und baue den um, so dass der niemals threadsafe benutzt werden kann:
Delphi-Quellcode:
unit SimpleParser;

interface

uses
  Classes,
  Parser;

type
  TParserState = procedure( AChar : Char ) of object;

  TSimpleParser = class( TInterfacedObject, IParser )
  private
    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

// unit-globale Variable und ich kann threadsafe vergessen
var
  FState : TParserState;

{ 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.
Hast du das in der DLL so ähnlich gelöst, dann kannst du das threadsafe vergessen.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: DLL und Threads

  Alt 18. Apr 2014, 14:01
Die Referenzzählung von Interfaces ist (meistens) Threadsicher, aber der Zugriff auf Methoden ist natprlich nicht vor gleichzeitigen Zugriffen geschützt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  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 12:46 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