Schrift
[thread]7831[/thread]

Mehrere Prozesse gleichzeitig auf eine Datei...

Leser: 2


<< |< 1 2 >| >> 17 Einträge, 2 Seiten
Fatso Keratso
 2006-03-27 16:16
#64092 #64092
User since
2006-03-27
18 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo,

ich korrigiere gerade den Quelltext meines kleinen CGI-Systems für meine Webseite und frage mich, was eigentlich in folgendem Fall geschieht:

Prozess A öffnet eine Datei zum Lesen und Schreiben '+<' und sichert sie mittels flock(FILE, LOCK_EX). Jetzt startet Prozess B und öffnet dieselbe Datei. Auch diese wird jetzt gesichert - flock(FILE, LOCK_EX). Prozess B muß jetzt, wenn ich daß richtig verstanden habe, warten bis Prozess A flock(FILE, LOCK_UN) aufruft.
Meine Frage: Wenn Prozess A jetzt die Datei löscht, wie reagiert Prozess B darauf, wenn der Prozess versucht die geöffnete Datei auszulesen, die Datei ja aber bereits gelöscht ist. Bekomme ich Leerdaten, einen Absturz (Code 500), oder wie?

Ich hoffe das ist jetzt verständlich. vielen Dank im Voraus für die Mühe.

Beste Grüße
Benjamin
GwenDragon
 2006-03-27 16:20
#64093 #64093
User since
2005-01-17
14538 Artikel
Admin1
[Homepage]
user image
Wenn Prozess A die Datei mit LOCK_EX gesperrt hat, kann Prozess B diese nicht öffnen, da sie exclusiv gesperrt ist.
Das open schlägt fehl.

Wiki:Dateien, Ein- und Ausgabe und
Wiki:Dateien sperren\n\n

<!--EDIT|GwenDragon|1143462209-->
die Drachin, Gwendolyn


Unterschiedliche Perl-Versionen auf Windows (fast wie perlbrew) • Meine Perl-Artikel

Fatso Keratso
 2006-03-27 16:48
#64094 #64094
User since
2006-03-27
18 Artikel
BenutzerIn
[Homepage] [default_avatar]
Verstehe (natürlich: Denkfehler!). Der Prozess B wird also nicht angehalten bis die Datei wieder frei ist, sondern es gibt einfach einen Fehler. Gibt es jetzt eine Möglichkeit für Prozess B herauszufinden, ob die Datei mit LOCK_EX gesichert ist. open() gibt ja meines Wissens nur true/false zurück. Ich würde gerne Prozess B warten lassen, bis Prozess A fertig ist und anschließend die Datei erneut vesuchen zu öffnen. Geht das irgendwie?
GwenDragon
 2006-03-27 17:06
#64095 #64095
User since
2005-01-17
14538 Artikel
Admin1
[Homepage]
user image
Semaphordatei benutzen.
In eine Datei, wenn sie noch nicht vorhanden ist, den Wert 0 schreiben. 0 bedeutet frei. Der Wert in der Datei ist der Semaphor.
Und immer schön die Semaphordatei bei jedem Schreiben vorher sperren!

Prozess A inkrementiert den Semaphor.
Wenn Prozess A beendet wird, nmuss der Semaphor wieder dekrementiert werden.
Prozess B fragt den Semaphor ab und solange er nicht Null ist, muss er warten.

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sub getSemaphor {
  my $fn = shift; # Dateiname
  open (SEM, "< $fn");
  flock( SEM, LOCK_EX);
  my $sem = <SEM>;
  close( SEM );
  return $sem;
}

sub setSemaphor {
  my $fn = shift; # Dateiname

  my $sem=getSemaphor($fn);
  open (SEM, "> $fn");
  flock( SEM, LOCK_EX);
  print SEM ++$sem; # Semaphor erhöhen und schreiben
  close( SEM );
  return $sem;
}


Wenn du allerdings auf sicher gehen willst, solltest du statt open ein sysopen benutzen, da kannst du dann auch direkt im sysopen Aufruf sperren.\n\n

<!--EDIT|GwenDragon|1143465811-->
die Drachin, Gwendolyn


Unterschiedliche Perl-Versionen auf Windows (fast wie perlbrew) • Meine Perl-Artikel

Fatso Keratso
 2006-03-27 17:12
#64096 #64096
User since
2006-03-27
18 Artikel
BenutzerIn
[Homepage] [default_avatar]
Stimmt. Einfach und effektiv. Vielen Dank auch :)
Dubu
 2006-03-28 00:20
#64097 #64097
User since
2003-08-04
2145 Artikel
ModeratorIn + EditorIn

user image
[quote=GwenDragon,27.03.2006, 14:20]Wenn Prozess A die Datei mit LOCK_EX gesperrt hat, kann Prozess B diese nicht öffnen, da sie exclusiv gesperrt ist.
Das open schlägt fehl.[/quote]
Wenn ich das richtig sehe (und richtig getestet habe), sind Locks sowohl unter Linux 2.6.x als auch unter Windows XP advisory, wie auch als "traditionelles Verhalten" in der Manpage beschrieben. Sie hindern also andere Prozesse nicht am Überschreiben oder Löschen einer Datei. Das open() im zweiten (dritten, vierten, etc.) Prozess kümmert sich also überhaupt nicht um das Lock, aber das anschließende flock() kehrt erst dann zurück, wenn der erste Prozess das Lock entfernt.

Fatso Keratso hat also auch recht mit seiner Vermutung, dass der zweite Prozess einfach "hängt", bis die Datei wieder freigegeben ist.

Zum Testen einfach das folgende Progrämmchen zweimal (oder mehr) parallel in zwei Shells starten:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl qw/:DEFAULT :flock/;

print "$$: Before open.\n";
sysopen (FILE, 'lockedfile', O_RDWR | O_CREAT) or die "$$: cannot open file: $!\n";

### Einfacher, legt die Datei aber nicht an, wenn sie noch nicht existiert:
# open FILE, '+<', 'lockedfile' or die "cannot open file (proc $$): $!\n";

print "$$: Before flock.\n";
flock FILE, LOCK_EX;
print "$$: Writing to file.\n";
print FILE "Here is process $$.\n";
print "$$: Sleeping.\n";
sleep 30;
print "$$: Closing file.\n";
close FILE;
print "$$: Finished.\n";

Man kann gut verfolgen, wie der als zweites gestartete Prozess im flock() wartet, bis der erste die Datei schließt (und damit das Lock implizit freigibt).

Ein zusätzliche Schicht mit Semaphoren halte ich für überflüssig.
Fatso Keratso
 2006-03-28 17:54
#64098 #64098
User since
2006-03-27
18 Artikel
BenutzerIn
[Homepage] [default_avatar]
Vielen Dank für das Testen. Ich probiere es gleich mal aus. Das bringt mich wieder zur ursprünglichen Frage, was passiert, wenn Prozess B nach der "Schlafphase", also flock(), wieder weiterläuft, die Datei aber von Prozess A bereits gelöscht wurde. Leerdaten zu bekommen wäre für mich okay, ein Absturz natürlich nicht. Wie könnte ich den dann verhindern?

Mir fällt aber auch gerade auf, daß sich der Fall ja recht leicht testen läßt ;) Das probiere ich mal.
Fatso Keratso
 2006-03-28 20:47
#64099 #64099
User since
2006-03-27
18 Artikel
BenutzerIn
[Homepage] [default_avatar]
Also: Shell gibt eine Fehlermeldung zurück, d.h. ja wohl auf dem Webserver wäre ein Fehler 500 aufgetreten. Wenn Prozess B also den Wartezustand beendet, werde ich also überprüfen, ob die Datei noch existiert, bevor ich versuche sie auszulesen.

if (-e $filename) {
print "$$: Datei existiert noch, also kann gelesen werden...\n";
}
else {
print "$$: Datei existiert nicht mehr, Filehandle ist ungültig\n";
}
Dubu
 2006-03-28 22:28
#64100 #64100
User since
2003-08-04
2145 Artikel
ModeratorIn + EditorIn

user image
Welches Betriebssystem hast du denn?
Unter Unix/Linux ist es kein Problem, wenn ein Prozess eine Datei löscht, während ein anderer Prozess noch ein Filehandle auf diese Datei auf hat: Der Verzeichniseintrag für die Datei wird direkt gelöscht, aber der Speicherplatz wird erst dann freigegeben, wenn das letzte Filehandle geschlossen ist.

Das wird einerseits gerne ausgenutzt für temporäre Dateien, die automatisch bei Programmende verschwinden: Ich öffne eine Datei und lösche sie gleich wieder; jetzt kann ich weiter das Filehandle zum Lesen und Schreiben benutzen, aber die Datei ist nicht im Filesystem zu sehen. Wenn mein Programm aus irgendwelchen Gründen abbricht, wird auch der Plattenplatz automatisch wieder freigegeben, ohne dass ich einen Interrupthandler zum Löschen bräuchte.

Andererseits kann es zu merkwürdigen Problemen führen: Die Festplatte ist fast voll. Ich suche nach Dateien, die gelöscht werden können. Eine große Logdatei brauche ich nicht mehr und lösche sie. Trotzdem nimmt der freie Speicherplatz nicht zu. Lösung des Rätsels: Der Prozess, der die Logdatei beschreibt, hält sie geöffnet. Erst wenn dieser Prozess die Datei schließt, wird auch der Speicherplatz freigegeben.

Das macht es unter Linux auch möglich, dass man Programme und Systembibliotheken aktualisiert, während sie benutzt werden. Deshalb empfiehlt es sich, nach einem Update wichtiger Bibliotheken nachzuschauen, ob irgendwelche Prozesse neu gestartet werden müssen. (Debian macht das meist automatisch, wenn die Dependencies stimmen.) Dies kann man z.B. mit lsof | grep '(deleted)' (lsof steht für "list open files").

Aber ich schweife ab...

Dein Test auf Existenz der Datei mit "-e" unterliegt selber wieder einer Race Condition: Ein anderer Prozess kann die Datei nach dem Test und vor dem Öffnen trotzdem löschen.

Mich würde aber interessieren, wie es unter Windows ist. Bricht da ein Programm ab, wenn es aus dem Filehandle einer gelöschten Datei liest?
esskar
 2006-03-28 22:57
#64101 #64101
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
[quote=Dubu,28.03.2006, 20:28]Mich würde aber interessieren, wie es unter Windows ist. Bricht da ein Programm ab, wenn es aus dem Filehandle einer gelöschten Datei liest?[/quote]
es kommt drauf an.

wenn man die Datei öffnet (geht nur über die WinAPI mit CreateFile(...)) und beim ShareMode NICHT FILE_SHARE_DELETE angibt, kann die Datei nicht gelöscht werden, solange das Handel auf ist => heißt ein DeleteFile wird nicht funktionieren und 0 zurückgeben.

wenn man eine Datei mit FILE_SHARE_DELETE öffnet, und die Datei wird gelöscht, dann liefert ein folgendes ReadFile oder WriteFile einen Wert kleiner 0, was man natürlich kontrollieren sollte.

wenn man einen ähnlichen Effect erreichen will wie dubu beschrieben hat - also dass die Datei gelöscht wird, sobald das Handle invalid wird (durch ein close, Beendigung des Programs, Absturz, ...) muss man bei CreateFile dem Parameter FlagsAndAttributes den Wert FILE_FLAG_DELETE_ON_CLOSE mitgeben
<< |< 1 2 >| >> 17 Einträge, 2 Seiten



View all threads created 2006-03-27 16:16.