|
|
SperrenWenn mehrere Prozesse in ein und derselben Datei Änderungen vornehmen wollen, wird es notwendig, Bereiche dieser Datei zu sperren. Diese Problematik ist bei den ersten Versionen von UNIX nicht berücksichtigt worden. Erst später beim Einsatz im kommerziellen Umfeld wurde die Notwendigkeit erkannt und in den verschiedenen UNIX-Dialekten unterschiedlich nachgereicht. So gibt es mehrere API-Aufrufe, um einen Dateibereich zu sperren. Relevant ist der Standard unter POSIX, den Sie bei Wahlmöglichkeit auch einsetzen sollten. Es kann aber durchaus passieren, dass Sie auf einen der anderen Sperrmechanismen in älteren Programmen stoßen, die aus Kompatibilitätsgründen oft noch funktionieren. Nicht jedes Dateisystem unterstützt Sperren. Insbesondere wenn es sich um ein Netzdateisystem handelt, kann es Schwierigkeiten geben. Aus diesem Grund sollte das Funktionieren der Sperren vor dem Einsatz in der Produktionsumgebung getestet werden.
Sperren nach POSIX
Die POSIX-Variante verwendet zum Sperren von Dateiausschnitten die Funktion
#include <fcntl.h> #include <unistd.h> #include <sys/types.h> fcntl(int dateihandle, int kommando, struct flock *sperre); Der Parameter kommando gibt die Funktion an und kann folgende Werte annehmen:
[Sperrfunktionalität]L|L
Konstante & Bedeutung
Die Elemente der Struktur flock geben die näheren Informationen über die Sperre an.
[Struktur flock]L|L|L
Element & Wert & Bedeutung
& SEEK_SET & vom Dateianfang
l_start & & Offset des Sperrbereichs
Das flock-Element l_pid liefert bei F_GETLK den Prozess, der die Sperre gesetzt hat. Als Beispiele dienen zwei Programme, die von zwei Terminalsitzungen aus gestartet werden. Das eine heißt one.c und das andere two.c. Zentraler Bestandteil der Programme ist die Funktion Sperren().
[Sperrfunktion Version 1] /* Sperren() aus one.c */ #include <unistd.h> #include <stdio.h>
int Sperren(char *name) { long data; int fh; struct flock sperre;
fh = open(name, O_RDWR, 0644); if (0<fh) { sperre.l_type = F_WRLCK; sperre.l_whence = SEEK_SET; sperre.l_start = 5*sizeof(data); sperre.l_len = sizeof(data); if (0> fcntl(fh, F_SETLK, &sperre)) { perror("Versuche die erste Sperre"); } getchar(); /* nun ist der Satz gesperrt */ sperre.l_type = F_UNLCK; if (0> fcntl(fh, F_SETLK, &sperre)) { perror("Löse die erste Sperre"); } close(fh); } else { perror("Kann Datei nicht öffnen"); } }
Das Programm
[Sperrfunktion Version 2] int Sperren(char *name) { long data; int fh; struct flock sperre;
fh = open(name, O_RDWR, 0644); if (0<fh) { puts("two: vor lock"); sperre.l_type = F_WRLCK; sperre.l_whence = SEEK_SET; sperre.l_start = 5*sizeof(data); sperre.l_len = sizeof(data); if (0> fcntl(fh, F_SETLKW, &sperre)) { perror("Versuche die zweite Sperre"); } puts("two: nach lock"); getchar(); sperre.l_type = F_UNLCK; if (0> fcntl(fh, F_SETLKW, &sperre)) { perror("Löse die zweite Sperre"); } close(fh); } }
Das Programm
Versuche die erste Sperre: Resource temporarily unavailable
Ganz offensichtlich blockiert Zuletzt soll bei einer bestehenden Sperre ermittelt werden, welcher Prozess die Sperre setzt. Dazu verwenden wir die Funktion Sniff():
[Blockade suchen] int Sniff(char *name) { long data; int fh; struct flock sperre;
fh = open(name, O_RDWR, 0644); if (0<fh) { sperre.l_type = F_WRLCK; sperre.l_whence = SEEK_SET; sperre.l_start = 5*sizeof(data); sperre.l_len = sizeof(data); if (0> fcntl(fh, F_GETLK, &sperre)) { perror("Problem bei fcntl"); } printf("Prozess: %dn", sperre.l_pid); close(fh); } }
lockf
Die Funktion
#include <sys/file.h> int lockf(int dateihandle, int kommando, off_t laenge); Der Parameter kommando wird mit einer Konstanten besetzt, die die Funktion angibt.
Mit dem Parameter laenge kann die Länge des zu sperrenden Bereichs festgelegt werden. Die Position innerhalb der Datei wird durch einen vorangehenden lseek() bestimmt.
flock
Diese Funktion zum Sperren von ganzen Datei wurde durch BSD 4.2 eingeführt.
flock(int dateihandle, int operation) Der Parameter operation kann folgende Werte annehmen.
Die Funktion gibt im Erfolgsfall 0 ansonsten -1 zurück. Nähere Informationen
finden Sie dann in der Variablen
locking
Die Funktion
int locking(int dateihandle, int kommando, long laenge); Der Parameter kommando kann folgende Werte annehmen.
[Sperroperation bei locking]L|L
Konstante & Bedeutung
Die Sperre wird ab der aktuellen Dateiposition gesetzt. Als eigenen Parameter
kennt
advisory und mandatoryEs gibt zwei Arten des Sperrens: advisory (übersetzt etwa empfohlen) und mandatory (übersetzt zwingend). Beim advisory locking wird der gesperrte Bereich nur dadurch geschützt, dass alle Programme, die auf die Datei zugreifen, nur über die Sperrmechanismen zugreifen. Greift ein anderer Prozess zu oder hält sich jemand nicht an diese Abmachung, hat die Sperre keinen Wert.
Beim Aktivieren des mandatory locking wird die Sperre durch das System
überwacht. Alle Dateizugriffe werden geprüft, um die Sperre zu schützen.
Mandatory locking wird mit denselben Aufrufen realisiert wie das advisory
locking. Der Umstieg erfolgt durch das Setzen der Dateiattribute.
Mit dem
chmod 2644 datendatei Letztlich ist das mandatory locking nicht so wichtig, wie man vielleicht auf den ersten Blick glaubt. Eine Datendatei wird normalerweise mit Programmen zugegriffen, die »wissen«, wie die Daten zu behandeln sind und damit auch darauf eingestellt sind, die Sperren konkurrierender Prozesse zu beachten. Alles andere ist definitiv ein Programmierfehler. Normalerweise wird nur dann mit Fremdprogrammen auf solche Dateien zugegriffen, wenn etwas schief gelaufen ist und eine Administration notwendig ist. Und in diesen Fällen würde ein mandatrory locking die Hilfe der entsprechenden Tools aussperren. Da das mandatory locking zusätzlich die Performance herabsetzt, wird es eher selten verwendet.
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|