AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi OLE Access Violation - Race Conditions?

OLE Access Violation - Race Conditions?

Ein Thema von beginnerXE1 · begonnen am 30. Sep 2021 · letzter Beitrag vom 17. Mär 2022
Antwort Antwort
beginnerXE1

Registriert seit: 22. Dez 2020
10 Beiträge
 
#1

OLE Access Violation - Race Conditions?

  Alt 30. Sep 2021, 18:26
Hallo liebe Delphi-Praktiker,

knapp ein Jahr nach dem erfolgreichen Kompilieren einiger Plugins eines alten Projekts ( https://www.delphipraxis.net/206450-...violation.html ) und ein paar weiteren .dll-Änderungen, komme ich nun an ein Problem, wo mir vielleicht ein wenig das Verständnis fehlt.

Ein Arbeitsschritt startet mehrere Threads einer Plugin.dll und beim Aufbau/Laden der Settings gleich zu Beginn kommt es anscheinend zu Race Conditions und in der Folge zu einer Access Violation / einem Lesefehler.
Die Settings werden jeweils aus einer .xml-Datei geladen, die für alle Threads dieselbe ist.
Fall 1: Wird nur 1 Thread gestartet, läuft alles problemlos durch.
Fall 2: Implementiere ich einen Mutex und begrenze den Zugang zu der Funktion "BuildSettingsClass", läuft alles ebenso problemlos durch.
Fall 3: Belasse ich das Laden im Original, kommt es zu den Fehlern, siehe weiter unten.

Mein Problem: am Settings-Laden habe ich nichts verändert zum ursprünglichen Code und mit der Original.dll tritt dieses Problem nicht auf. Meine Änderung ist in einer anderen Datei und hat nichts mit dem Laden zu tun. Zu meiner kleinen Code-Änderung kommt das Plugin gar nicht, weil es beim Laden der Settings schon zu Problemen kommt. Ich kann die Threads auf 1 begrenzen, aber diese Notlösung nervt, ebenso wie der Einbau eines Mutex, wenn es nicht unbedingt sein muss.

Ich habe das Problem mit der Plugin.dll sowohl mit der von Delphi 2010 als auch Delphi 10.3 erzeugten eigenen DLL.
Den Fall 3 habe ich insofern eingegrenzt, indem ich nach jeder Zeile einen Counter erhöht und mir im Fehlerfall / am Funktionsende habe ausgeben lassen. Im Bereich "Verarbeitung" wechselt der Fehlerpunkt immer wieder, aber frühstens immer beim LoadFromFile der XML-Datei.

Mein Verdacht ist, dass das Laden derselbe XML-Datei trotz CoInitializeEx und der Verwendung von NewXMLDocument sowie LoadFromFile nicht Thread-safe ausgeführt wird, aber wenn ich mir nach "NewXMLDocument" mittels "Format('%p', [@XMLDoc])" die Adresse ausgeben lasse (zusammen mit meinem Counter), zeigen beide Threads auf unterschiedliche Adressen.

Vereinfachter Code und hoffentlich auf das Notwendigste begrenzt:
Delphi-Quellcode:
class function TSettingsMisc.BuildSettingsClass(const AFileName: TFileName; const ASettings: TSettings): Boolean;
var
  PerformUnInit: Boolean;
  XMLDoc: IXMLDocument;

  PropCount: Integer;
  PropList: PPropList;
  {...}
begin
  Result := False;
  PerformUnInit := Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED));
  try
    XMLDoc := NewXMLDocument;
    try
      with XMLDoc do
      begin
        NodeIndentStr := #9;
        Options := Options + [doNodeAutoIndent];
        LoadFromFile(AFileName);
        Active := True;
      end;

      // ab hier meiner Meinung nach irrelevant, "Verarbeitung" mit Zugriff auf verschiedene PropList-Pointer.
       // map xml to settings class
        // based on http://stackoverflow.com/questions/10188459/how-to-loop-all-properties-in-a-class
     
        PropCount := GetPropListCount(ASettings.ClassInfo, PropList);
        GetMem(PropList, PropCount * Sizeof(Pointer));
        try
          GetPropList(ASettings.ClassInfo, PropList);
          { ... }
        finally
          FreeMem(PropList);
        end;
     // "Verarbeitung Ende"
    finally
      XMLDoc := nil;
    end;
  finally
    if PerformUnInit then
      CoUninitialize;
  end;
end;
Ich hoffe, ich habe nichts vergessen / zu viel gekürzt.
Falls jemand auf Anhieb eine Idee hat, wäre ich sehr dankbar. Ich habe über den Counter versucht zu debuggen, weil ich mir nicht sicher war, ob ich beim Delphi Debugger nicht auf diese "Race Condition" einwirke, sofern es eine ist.

Vielen Dank!
PS: Falls es das falsche Unterforum ist, entschuldige ich mich dafür.
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.400 Beiträge
 
Delphi 7 Professional
 
#2

AW: OLE Access Violation - Race Conditions?

  Alt 30. Sep 2021, 19:25
Hilft sowas Using Critical Sections. ums LoadFromFile herum?

Wenn XMLDoc beim LoadFromFile Exklusivrechte (oder so) auf die Datei beansprucht, könnte das ein Grund für die von Dir beobachtete Problematik sein. Könnte, muss aber nicht.
  Mit Zitat antworten Zitat
beginnerXE1

Registriert seit: 22. Dez 2020
10 Beiträge
 
#3

AW: OLE Access Violation - Race Conditions?

  Alt 30. Sep 2021, 23:38
Vielen Dank für deine Antwort!

Zunächst muss ich mich korrigieren: der Fehler tritt nicht frühstens bei "LoadFromFile" auf sondern bei "NewXMLDocument". Das habe ich vorhin durcheinander gebracht.
Zudem ist die Fehlermeldung zwar immer "EOleException - ungültige Zeigeroperation", aber im Detail wechselt "Exception.ToString" zwischen "Zugriffsverletzung an.. Lesen von..." und "Schwerwiegender Fehler". Gibt es da noch eine Möglichkeit, mehr Informationen zu erhalten?

Ich habe ansonsten deinen Vorschlag, mit einer CriticalSection mal probiert, allerdings ohne Ergebnis. Nachdem ich es gerade aber noch mal nachgelesen habe, war meine Implementierung wohl schlichtweg falsch, weil ich die CriticalSection als lokale Variable definiert hatte, was natürlich für separate Threads nichts bringt.
Leider habe ich aber auch nur Zugriff auf die .DLL und nicht auf das Hauptprogramm. Damit ist es mir doch gar nicht möglich, die CriticalSection so zu definieren, dass beide DLL-Threads sich das Lock teilen, oder?

Was ich aber natürlich machen kann, ist meine Lösung aus Fall 2 mit dem Mutex mal um NewXMLDocument zu setzen. Leider kam mir die Idee erst beim Aufschreiben der Antwort... Da ein Thread meistens durchkommt und erst der 2. abbricht und in der Hälfte der Fälle erst während der "Verarbeitung" einen Fehler erzeugt, grübel ich darüber, ob es wirklich an der Funktion "NewXMLDocument" liegen kann.
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.400 Beiträge
 
Delphi 7 Professional
 
#4

AW: OLE Access Violation - Race Conditions?

  Alt 1. Okt 2021, 10:59
Frag' bitte mal die Suchmaschine Deiner Wahl nach xmldocument thread safe, mir scheint, Du bist mit der Problematik nicht allein.

Da fand ich u. a. sowas:
Zitat:
Is the XMLDocument thread-safe? - …
https://social.msdn.microsoft.com/Fo...08ee-4b53-8ae5...

21.02.2007 · As well none of INSTANCE methods are thread-safe in any of .Net APIs almost. All Static members are considered to be thread-safe. But, IMHO, When you are doing some kind of read and write operation parellel (using multiple threads) then its important to synchronize the operations making it thread-safe but when you are doinng parellel write operations ONLY -OR …
Was Du da jetzt konkret in Deinem Fall machen musst: Da hab' ich schlicht und einfach nicht den leisesten Ansatz einer Ahnung, geschweigendenn sowas wie Wissen
  Mit Zitat antworten Zitat
beginnerXE1

Registriert seit: 22. Dez 2020
10 Beiträge
 
#5

AW: OLE Access Violation - Race Conditions?

  Alt 17. Mär 2022, 16:36
Spät, später, heute...

Vielen Dank für deine Antwort damals, Delphi.Narium. Mit der Problematik war ich tatsächlich nicht allein, aber keiner der Hinweise führte zum Erfolg. Zeitmangel führte dann zur fehlenden Antwort und keinen neuen Erkenntnissen.

Kürzlich hatte ich wieder etwas Zeit und habe das Lesen der XML ausgelagert in einen eigenen StreamReader mit Shared-Access, aber am Fehlerbild hatte sich nichts geändert. Da es also nicht am Einlesen/Laden der XML lag, hatte ich keinen weiteren Ansatzpunkt mehr und bin zurück zu den Anfängen und Grundlagen gegangen.

Über https://www.oreilly.com/library/view...6595/ch04.html bin ich auf die Lösung "isMultiThread" gestoßen:
Zitat:
In a multithreaded application or library, you must be sure that the global variable IsMultiThread is True. Most applications do this automatically by calling BeginThread or using the TThread class. If you write a DLL that might be called from a multithreaded application, though, you might need to set IsMultiThread to True manually.

Allocating memory (with GetMem or New) and freeing memory (with FreeMem and Dispose) is thread-safe. Delphi automatically protects its memory allocator for use in multiple threads (if IsMultiThread is True, which is one reason to stick with Delphi’s BeginThread function instead of using the Windows API CreateThread function).
Also erst mal kontrolliert, was isMultiThread zurückliefert: False. Nach dem Einfügen von "isMultiThread := True;" gleich nach "begin" in der DLL-Hauptdatei blieben die Fehler aus. Es waren also keine Race Conditions, wie ich vermutet hatte, sondern Zugriffsfehler durch geteiltes Speichermanagement. Ich verstehe leider nicht, wieso die Fehler früher oder bei den ursprünglichen .dlls nicht aufgetreten sind und nicht auftreten sondern nur bei den neu erstellten, aber vielleicht werden heutzutage mehr Optimierungen vorgenommen. Das Flag wurde damals nicht gesetzt und der Aufruf der .dlls hat sich auch nicht geändert.

Ich hoffe, dass die Rückmeldung vielleicht anderen noch etwas Zeit und Kopfzerbrechen erspart: CoInitializeEx + isMultiThread.

Geändert von beginnerXE1 (17. Mär 2022 um 16:41 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 10:34 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