Autor Beitrag
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Sa 15.03.08 23:06 
Ich habe ein Programm geschrieben, welches mehrfach ausgeführt werden kann.
Dieses Programm erstellt Logeinträge, bei bestimmten Ereignissen und schreibt sie in eine Datei (name.log)

Das Problem ist: Es kann passieren, dass mehrere Instanzen zu gleichen Zeit auf die Datei zugreifen. Wie kann ich verhindern dass das Programm dann abstürzt oder ein Log-Eintrag fehlt?
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: So 16.03.08 11:04 
Falls es dir nicht zu aufwendig ist kannst du eine Datenbank verwenden, die simultanen Zugriff unterstützt - dann musst du dir darüber keine Gedanken machen.

AXMD
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 16.03.08 11:07 
user profile iconFlamefire hat folgendes geschrieben:
Ich habe ein Programm geschrieben, welches mehrfach ausgeführt werden kann.
Dieses Programm erstellt Logeinträge, bei bestimmten Ereignissen und schreibt sie in eine Datei (name.log)

Das Problem ist: Es kann passieren, dass mehrere Instanzen zu gleichen Zeit auf die Datei zugreifen. Wie kann ich verhindern dass das Programm dann abstürzt oder ein Log-Eintrag fehlt?


Sollen denn alle Instanzen in dieselbe Datei schreiben?

Wenn nicht, kannst Du z.B. die aktuelle Process-ID als Teil des Dateinamens verwenden, dann ist die Datei jeweils pro Instanz eindeutig.

Wenn doch, musst Du irgendwie synchronisieren, z.B. mittels eines benannten Mutex-Objekts, das die erste Instanz erzeugt und alle anderen Instanzen oeffnen. Zugriff auf die Log-Datei bekommt dann nur der, dem das Mutex gehoert.

twm
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 16.03.08 12:07 
nein es soll einfach bleiben
also keine db einfach eine .log datei

und ja sie schreiben alle in eine datei
das mit der PID hab ich auch überlegt...aber dann hätte man i-wann 100erte logs

und alle brauchen den dateizugriff
ich will am besten also nur warten bis die datei frei ist
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 16.03.08 12:20 
user profile iconFlamefire hat folgendes geschrieben:
nein es soll einfach bleiben
also keine db einfach eine .log datei

und ja sie schreiben alle in eine datei
das mit der PID hab ich auch überlegt...aber dann hätte man i-wann 100erte logs

Du koenntest einfach beim Programmstart alle Log-Dateien loeschen, die aelter als n Tage/Stunden sind.
Zitat:

und alle brauchen den dateizugriff
ich will am besten also nur warten bis die datei frei ist


Du koenntest die Datei jedesmal neu oeffnen, schreiben und wieder schliessen. Beim Oeffnen dann ShareDenyWrite angeben und schon kann keine andere Instanz reinschreiben (Lesen geht immernoch). Dann musst Du aber den moeglichen Fehler beim Oeffnen der Datei abfangen und es solange wieder versuchen, bis es geklappt hat. Das ist potentiell sehr langsam, ein Mutex ist performanter.

Was sinnvoll ist, haengt sehr stark davon ab, was das Programm eigentlich macht. Evtl. kann es sogar sinnvoll sein, den Aufruf der einzelnen Instanzen zu serialisieren, so dass sie gar nicht mehr parallel laufen.

twm
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 16.03.08 12:22 
z.zt. benutze ich diese funktion:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure Log(Text: string);
var f: TextFile;
begin
  {$IOChecks OFF}
  FBufferCritSect.Enter;
  try
    AssignFile(f, 'test.log');
    if FileExists('test.log') then
      Append(f)
    else
      Rewrite(f);
    Text := DateToStr(Date) + ' ' + TimeToStr(Time) + ': ' + Text;
    WriteLn(f, Text);
    CloseFile(f);
  finally
    FBufferCritSect.Leave;
  end;
  {$IOCHECKS ON}
end;


Kannst du mir da kurz zeigen, wie du das meinst?
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 16.03.08 14:53 
user profile iconFlamefire hat folgendes geschrieben:
z.zt. benutze ich diese funktion:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure Log(Text: string);
var f: TextFile;
begin
  {$IOChecks OFF}
  FBufferCritSect.Enter;
  try
    AssignFile(f, 'test.log');
    if FileExists('test.log') then
      Append(f)
    else
      Rewrite(f);
    Text := DateToStr(Date) + ' ' + TimeToStr(Time) + ': ' + Text;
    WriteLn(f, Text);
    CloseFile(f);
  finally
    FBufferCritSect.Leave;
  end;
  {$IOCHECKS ON}
end;


Die CriticalSection bringt nur dann was, wenn innerhalb des Programms mehrere Threads verwendet werden. Wenn es nur single threaded ist, kannst Du sie einfach weglassen.
Zitat:

Kannst du mir da kurz zeigen, wie du das meinst?


Wie ich was meine?

twm
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 16.03.08 15:49 
die critical sections sind, weil mein programm auch noch mehrere threads hat ^^

Zitat:
Du koenntest die Datei jedesmal neu oeffnen, schreiben und wieder schliessen. Beim Oeffnen dann ShareDenyWrite angeben und schon kann keine andere Instanz reinschreiben (Lesen geht immernoch). Dann musst Du aber den moeglichen Fehler beim Oeffnen der Datei abfangen und es solange wieder versuchen, bis es geklappt hat. Das ist potentiell sehr langsam, ein Mutex ist performanter.

wie müsste diese funktion aussehen?
toms
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1099
Erhaltene Danke: 2



BeitragVerfasst: So 16.03.08 16:31 
Hallo, ich verwende den Suche in der Delphi-PRAXiS TEXCLUSIVEFILESTREAM von shima

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
uses
   FileStreamUtils;

procedure AddLog(LogFile, LogText: string);
var
  logStream: TExclusiveFileStream;
begin
  logStream := TExclusiveFileStream.Create(LogFile, 10000);
  try
    logStream.SeekToEnd;
    LogText := LogText + #13#10;
    logStream.WriteBuffer(LogText[1], Length(LogText));
  finally
    logStream.Free;
  end;
end;
Einloggen, um Attachments anzusehen!
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 16.03.08 18:20 
was macht die unit genau?
Ich möchte ja einerseits doppelzugriff zur gleichen zeit verhindern, als auch sicherstellen, dass alle logeinträge gemacht werden
toms
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1099
Erhaltene Danke: 2



BeitragVerfasst: So 16.03.08 18:32 
user profile iconFlamefire hat folgendes geschrieben:
was macht die unit genau?
Ich möchte ja einerseits doppelzugriff zur gleichen zeit verhindern, als auch sicherstellen, dass alle logeinträge gemacht werden



* Falls die Datei noch nicht exisitiert, wird sie erzeugt
* der Zugriff erlaubt immer Lese- & Schreibzugriff
* kein anderer Prozess kann die Datei lesen oder schreiben, solange ein Objekt der Klasse existiert
* es kann ein Timeout angegeben werden. Innerhalb dieser Zeit (in ms) wird versucht die Datei zu öffnen/erzeugen. übliche Zeiten liegen zwischen 200ms und 10s.
* Während des Wartens, bis die Datei frei wird, wird das Event OnWait "abgefeuert". Dies erlaubt dem Programm, das Warten sichtbar zu machen
* Falls die Datei nicht geöffnet werden konnte, enthält die Exception ein aussagekräfte Meldung, warum es nicht geklappt hat
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 16.03.08 18:36 
Warum hast du denn nicht einmal in die Unit hineingeschaut? :roll:
Dann hättest du gesehen, dass dort genau das gemacht wird, was bereits vorgeschlagen wurde: Es wird in einer Schleife gewartet bis die Datei erfolgreich exklusiv geöffnet werden konnte oder der angegebene Timeout abgelaufen ist...

// EDIT:
Da stehts ja schon genauer^^
Flamefire Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: So 16.03.08 19:03 
perfekt
vielen dank
sry aber bevor ich was lade will ich wissen was es ist ^^