Hallo Zusammen,
ich habe ein etwas kompliziertes Konstrukt:
Thread1 prüft alle 60 Sekunden, ob die Zeit für einen oder mehrere Berichte erreicht wird.
--> Wenn True, dann erstellt Thread1 so viele Threads, wie Berichte erstellt werden sollen. Wir nennen sie Thread2
--> Dabei wird für jeden Thread ein ReportObject created, durch welches der Report erstellt wird.
Von Thread2 können also beliebig viele parallel laufen.
Thread2 lässt das ReportObject den Bericht erstellen. Dabei wird am Anfang immer ein TAdvStringGrid (TMS Components) erstellt, dass am Ende der Berichtserstellung mit Daten gefüllt wird, und das am Ende eine formatierte Excel-Datei absprichert und per Mail versendet. Das StringGrid wird nie irgendwo in einer Form gezeigt, sondern ist nur virtuell.
Und bei dem TAdvStringGrid.Create(nil) kommt es in unregelmäßigen Abständen zu Exceptions, bei denen ich keinen Zusammenhang erkennen kann. Es kann sein, dass das Ganze fünf Mal problemlos klappt und beim sechsten Mal kommt immer an dieser Stelle eine
Exception:
Zitat:
Zugriffsverletzung bei Adresse 0047F999 in Modul 'BD_VersandServer.exe'. Lesen von Adresse 00000008
Jetzt habe ich mir überlegt, dass StringGrid.Create vielleicht nicht threadsicher ist und habe in dem ReportObject ein privates DatenGrid: TAdvStringGrid definiert, welches ich immer beim Create des ReportObjectes mit create. Da das ReportObject eine Variable des Thread2 ist und im Zuge der Erstellung des Thread2 auch erstellt wird, passiert das hübsch nacheinander und nicht zeitgleich.
Delphi-Quellcode:
for I := 1 to Length(fSections) -1 do begin //Erster Eintrag ist Überschrift der INI-Datei
LogText:= Logic.SetLogText_CR(JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].ReportName'), JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].KundenNr'), '', 57);
///Daily Reports
if JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].Activ') = '1' then begin
if JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].RepeatInterv') = 'daily' then begin
SendTime:= FormatDateTime ('hh:nn', Now);
SendDay:= FormatDateTime ('dddd', Now);
VDay:= FormatDateTime ('dddd', Now);
VZeit:= JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].DailyTime');
if (JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].Weekend') = '1') or //Wenn Weekend = 1 immer ausführen
((JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].Weekend') = '0') and //Wenn Weekend = 0 nur Mo - Fr
((VDay <> 'Samstag') and
(VDay <> 'Sonntag'))) then begin //Ohne Wochenende
if (Pos(SendTime, VZeit) > 0) then begin
J:= Length(ArryRprtThrd) -1;
SetLength(ArryRprtThrd, J + 1);
Logic.SendLogMessage(fWriteCRLog, LogText + ' STARTED', fCRMemoName);
//Report Execute-Thread erstellen
ArryRprtThrd[J]:= TThreadExcCstRprts.Create(true);
ArryRprtThrd[J].FreeOnTerminate:= true;
ArryRprtThrd[J].JSValGenSet:= fJSValGenSet;
ArryRprtThrd[J].Report:= TRprtCrtr.Create(fJSValGenSet, JSValCustSet, JSValCRSet, fWriteCRProt, fWriteCRLog, fCRMemoName, fMailSGName); //ReportObject
ArryRprtThrd[J].ReportID:= fSections[I];
ArryRprtThrd[J].KdNr:= JSValCRSet.GetValue<string>(fSections[0] + '.' + fSections[I] + '[0].KundenNr');
ArryRprtThrd[J].CRMemoName:= fCRMemoName;
ArryRprtThrd[J].CRSGName:= fCRSGName;
ArryRprtThrd[J].WriteCRProt:= fWriteCRProt;
ArryRprtThrd[J].WriteCRLog:= fWriteCRLog;
ArryRprtThrd[J].Resume;
end
else begin
//Logic.SendLogMessage(fWriteCRLog, LogText + ' CHECKED', fCRMemoName);
end;
end
else begin
Logic.SendLogMessage(fWriteCRLog, 'No Check by Weekend', fCRMemoName);
end;
end
Durch die For-Schleife, in der die Thread2 erstellt werden, werden diese schön nacheinander erstellt und das TAdvStringGrid.Create wird nicht parallel aufgerufen...
Create des ReportObject jetzt mit Create des privaten StringGrids
Delphi-Quellcode:
constructor TRprtCrtr.Create(JSValueGenSet, JSValueCustSet, JSValueCRSet: TJSONValue; WriteCRProt: TWriteCRProt; WriteCRLog: TWriteCRLog; mmName, SGName: string);
begin
if Assigned(JSValueCRSet) then
SetJSValCRSet(JSValueCRSet);
if Assigned(JSValueCustSet) then
SetJSValCustSet(JSValueCustSet);
if Assigned(JSValueGenSet) then
SetJSValGenSet(JSValueGenSet);
if (Assigned(WriteCRProt)) and (SGName <> '') then
SetWriteCRProt(WriteCRProt);
if (Assigned(WriteCRLog)) and (mmName <> '') then
SetWriteCRLog(WriteCRLog);
SetmmName(mmName);
SetSGName(SGName);
fSGReportDaten:= TAdvStringGrid.Create(nil);
end;
Im ersten Test hat es geklappt, aber ich wollte Euch fragen, ob Ihr wisst, ob StringGrid.Create threadsicher ist oder nicht.
Vielen Dank
Patrick