Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh (https://www.delphipraxis.net/179218-der-zugriff-auf-eine-tsringlist-ist-auf-einmal-nicht-mehr-moeglixh.html)

ByTheTime 20. Feb 2014 18:40

Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
Hallo,
Titelwahl ist mir immer etwas schwer gefallen, aber ich versuche mal mein Problem genau zu schilder :stupid:

Also, ich habe einen Service. Dort ist eine TStringList (genannt "MInfo") global deklariert. Es laufen insgesamt 3 Threads (Primärer Thread + 2 sekundäre Threads). Das sage ich extra dazu, weil die erste Reaktion wahrscheinlich wäre, das ich beim Threadhandling Mist gebaut habe, allerdings wird die StringList nur innerhalb eines Threads genutzt.

Nun passiert folgendes: Eine Funktion wird ausgeführt (genannt RunCaptured) und wandelt den Inhalt einer PDF-Datei in Text um.

Delphi-Quellcode:
function TEventThread.RunCaptured(const _dirName, _exeName,
  _cmdLine: string): Boolean;
var
  Start: TStartupInfo;
  procInfo: TProcessInformation;
  tmpName: string;
  tmp: THandle;
  tmpSec: TSecurityAttributes;
  res: TStringList;
  return: Cardinal;
begin
  Result := False;
  try
    { Setze ein Temporäres File }
    { Set a temporary file }
    tmpName := 'Test.tmp';
    FillChar(tmpSec, SizeOf(tmpSec), #0);
    tmpSec.nLength := SizeOf(tmpSec);
    tmpSec.bInheritHandle := True;
    tmp := CreateFile(PChar(tmpName), GENERIC_WRITE, File_Share_Write, @tmpSec,
      Create_Always, FILE_ATTRIBUTE_NORMAL, 0);
    try
      FillChar(Start, SizeOf(Start), #0);
      Start.cb := SizeOf(Start);
      Start.hStdOutput := tmp;
      Start.dwFlags := StartF_UseStdHandles or StartF_UseShowWindow;
      Start.wShowWindow := SW_Minimize;
      { Starte das Programm }
      { Start the program }
      if CreateProcess(nil, PChar(_exeName + ' ' + _cmdLine), nil, nil, True,
        CREATE_NO_WINDOW, nil, PChar(_dirName), Start, procInfo) then
      begin
        SetPriorityClass(procInfo.hProcess, Idle_Priority_Class);
        WaitForSingleObject(procInfo.hProcess, Infinite);
        GetExitCodeProcess(procInfo.hProcess, return);
        Result := (return = 0);
        CloseHandle(procInfo.hThread);
        CloseHandle(procInfo.hProcess);
        CloseHandle(tmp);
        { Die Ausgaben hinzufügen }
        { Add the output }
        res := TStringList.Create;
        try
          res.LoadFromFile(tmpName);
          MInfo.Clear;
          MInfo := res; // AUSGABE!!!
          Log(True, 'INFORMATION: Count of res = ' + IntToStr(res.Count) + '!');
          Log(True, 'INFORMATION: Count of MInfo = ' +
            IntToStr(MInfo.Count) + '!'); // Anzahl der Zeilen in LogDatei speichern
        finally
          res.Free;
        end;
        DeleteFile(PChar(tmpName));
      end
      else
      begin
        Log(True, 'ERROR: ' + PChar(SysErrorMessage(GetLastError())));
      end;
    except
      on E: Exception do
      begin
        Log(True, Format('ERROR: [%s] "%s"', [E.Classname, E.Message]));
        CloseHandle(tmp);
        DeleteFile(PChar(tmpName));
      end;
    end;
  finally
  end;
end;
Das funktinoert auch alles wunderbar, am Ende wird mir im Log angezeigt, das MInfo 500 Zeilen hat.

Nach dem Ausführen dieser Routine wird eine weitere Routine augeführt, die folgendermassen anfängt:

Delphi-Quellcode:
procedure TEventThread.ExtractInfo(JobID: Integer);
var
  s: String;
  i, j, k, l, EventID: Integer;
begin
  LPuffer.Clear;
  LCourses.Clear;
  LCourses.CommaText := Jobs[JobID].Courses;

  Log(True, 'INFORMATION: Count of MInfo = ' + IntToStr(MInfo.Count) + '!'); // Hier kommt es zu einem Fehler!

  if ((MInfo.Text <> EmptyStr) and (LCourses.Count <> 0)) then // !!!
  begin
  {...}
In der im Code makierten zeile, kommt es zu einer EAccessViolation. Hier wollte ich nochmals die Anzahl der Zeilen von MInfo im Log speichern. Entferne ich diese Zeile kommt es in der nächsten Zeile aufgrund von "MInfo.Text" ebenfalls zu einer EAccessViolation. Ich kann mir aber nicht erklären warum! MInfo wird nur an diesen beiden Stellen verwendet. :?:

Hoffe jemand hat eine Idee :)

[EDIT] Hier nochmal die Exception: "Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000" Aber das hilft auch nicht viel weiter :/

Gruß,
Lukas

Union 20. Feb 2014 18:45

AW: Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
Delphi-Quellcode:
 
          MInfo := res; // AUSGABE!!!  <<<< Deswegen und...
          Log(True, 'INFORMATION: Count of res = ' + IntToStr(res.Count) + '!');
          Log(True, 'INFORMATION: Count of MInfo = ' +
            IntToStr(MInfo.Count) + '!'); // Anzahl der Zeilen in LogDatei speichern
        finally
          res.Free; // <<<<<< ... Deswegen
Du weist erst res zu MInfo zu und danach zerstörst Du die StringListe. Das ist beides die selbe Referenz! Verwende
Delphi-Quellcode:
Assign
oder stell Die Logik entsprechend um.

Sir Rufo 20. Feb 2014 18:47

AW: Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
Wenn nur ein Thread diese StringList nutzt, warum ist die dann global deklariert und nicht privat innerhalb dieses Threads?
Dann kannst du dir sicher sein, dass kein anderer diese benutzt.

Der schöne Günther 20. Feb 2014 18:48

AW: Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
In deiner Zeile
Delphi-Quellcode:
MInfo := res; // AUSGABE!!!
biegst du deine Referenz "Minfo" auf deine TStringList "res" um. Unter "res" und "Minfo" erreichst du jetzt ein und dieselbe TStringList. Und wenig später gibst du res frei. Dein "Minfo" zeigt jetzt auf einen Haufen Müll.

Wenn du jetzt später MInfo benutzt, knallt es.

Du musst an dieser Stelle den Inhalt von "res" in "Minfo" vollständig kopieren.


//Edit: Gott, was sind wir alle schnell :-)

Union 20. Feb 2014 18:56

AW: Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1248869)
//Edit: Gott, was sind wir alle schnell :-)

Ja, uns ist wohl langweilig.

ByTheTime 20. Feb 2014 20:37

AW: Der Zugriff auf eine TSringList ist auf einmal nicht mehr möglixh
 
:wall: Klappt, super danke :) Hatte es sogar vorher richtig, habe es aber gestern geändert um was auszuprobieren und vergessen wieder rückgängig zu machen.

@SirRufo: Normalerweiße wird die StringList noch von einem anderen Thread verwendet, was ich aber bewusst verschwiegen habe, da der Thread im Moment nicht aktiv ist (Weil ich ihn schlicht und einfach für meine Testzwecke rausgenommen hab).


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:53 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