Galileo Computing < openbook >
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung


'Wie werde ich Unix-Guru' als Buch bestellen
A. Willemer
Wie werde ich UNIX-Guru
I  ANWENDUNG
Know-How für Unix/Linux-User: Einführung, Shell, Befehle, Hilfe, Arbeit mit Dateien, Editoren, Reguläre Ausdrücke, nützliche Tools, Hardware.

II  ADMINISTRATION
Tools, Systemstart, Benutzer verwalten, Hardware konfigurieren, Software installieren, Datensicherung, Tuning, Kernel

III  NETZWERK
Client/Server Systeme, TCP/IP, Routing, IPv6, Internet-Dienste, DHCP, Webserver, Firewalls

IV  DAS X-WINDOW SYSTEM
Die grafische Oberfläche von UNIX einrichten und nutzen

V  PROGRAMMIERUNG VON SHELLSKRIPTEN
Automatisieren von Tasks durch Shell-Skripte.

VI  PERL
Interpreter, Syntax, Variablen, Steuerung, Funktionen, UNIX-Aufrufe, GUIs mit Tk

VII  PROGRAMMIERWERKZEUGE
C-Compiler, Analyse-Tools, CVS, yacc, diff

VIII  UNIX-SYSTEMAUFRUFE
UNIX-Befehle in eigenen Programmen nutzen

IX  LITERATUR
Weiterführende Literatur zu UNIX und LINUX

 
Galileo Computing / <openbook> / "Wie werde ich UNIX-Guru ?"
« Dateieigenschaften ändern Dateizugriffe Link erzeugen: link, symlink »

Unterabschnitte
  • Sperren nach POSIX
  • lockf
  • flock
  • locking
  • advisory und mandatory

Sperren

Wenn 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 fcntl().

#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
F_GETLK & Ermittle, ob eine Sperre gesetzt ist
F_SETLK & Eine Sperre setzen oder Fehler zurückgeben
F_SETLKW & Eine Sperre setzen oder warten

Die Elemente der Struktur flock geben die näheren Informationen über die Sperre an.

[Struktur flock]L|L|L Element & Wert & Bedeutung
& F_WRLCK & exklusiv
l_type & F_RDLCK & geteilt, verhindere Schreibzugriff
& F_UNLCK & Sperre aufheben

& SEEK_SET & vom Dateianfang
l_whence & SEEK_CUR & ab aktueller Dateiposition
& SEEK_END & vom Dateiende

l_start & & Offset des Sperrbereichs
l_len & & Länge des Bereichs, bei 0 bis Dateiende

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 one wird gestartet und bleibt in der Funktion Sperren() an der Stelle stehen, wo es mit getchar() auf die Returntaste wartet. In dieser Zeit wird auf der zweiten Konsole das Programm two gestartet. Dessen Funktion Sperren() sieht nur geringfügig anders aus:

[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 two wird »two: vor lock« ausgeben und dann stehen. Es blockiert also an der von one gesetzten Sperre. Wird das Programm one durch Drücken der Returntaste weitergeführt, gibt es die Sperre frei und two meldet sich mit »two: nach lock«. Nun hält Programm two die Sperre. Starten Sie jetzt das Programm one, erhalten Sie die folgende Meldung:

Versuche die erste Sperre: Resource temporarily unavailable

Ganz offensichtlich blockiert one nicht, sondern bekommt eine Fehlerrückgabe durch fcntl(). Das hängt damit zusammen, dass die Sperre im Programm one.c mit dem Kommando F_SETLK angefordert wird, die nicht blockiert, wenn die Sperre gesetzt ist, sondern eine Fehlermeldung liefert. Dagegen arbeitet two.c mit dem Kommando F_SETLKW. Dann blockiert der Prozess, bis die Sperre wieder freigegeben wird.

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 lockf wurde durch System V eingeführt. Sie wird von manchen Systemen, beispielsweise Linux, als weitere Schnittstelle zu den POSIX-Sperren akzeptiert. Neue Entwicklungen sollte man dennoch auf POSIX ausrichten.

#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.

  • [F_LOCK] Setzt eine exklusive Sperre. Ist der Bereich bereits gesperrt, blockiert der Prozess. So ist gewährleistet, dass nur ein Prozess eine Sperre setzen kann.
  • [F_TLOCK] Setzt wie F_LOCK eine exklusive Sperre. Bei einer bereits vorliegenden Sperre blockiert der Prozess aber nicht. Statt dessen gibt die Funktion einen Fehler zurück.
  • [F_ULOCK] Hebt die Sperre auf.
  • [F_TEST] Prüft, ob eine Sperre auf diesem Bereich liegt. Die Funktion gibt -1, wenn ein anderer Prozess die Sperre gesetzt hat. Der Rückgabewert 0 bedeutet, dass keine Sperre vorliegt oder die Sperre vom eigenen Prozess stammt.

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 sperrt nicht einen Ausschnitt, sondern die komplette Datei.

flock(int dateihandle, int operation)

Der Parameter operation kann folgende Werte annehmen.

  • [LOCK_SH] Shared lock. Mehrere Prozesse können parallel sperren. Dies ist eine eher ungewöhnliche Operation und macht nur im Zusammenhang mit mandantory locking (siehe unten) Sinn.
  • [LOCK_EX] Exclusive lock. Nur ein Prozess kann sperren.
  • [LOCK_UN] Unlock. Die Sperre wird aufgehoben.
  • [LOCK_NB] Nonblocking . Die Operation blockiert nicht, sondern gibt eine Fehlermeldung zurück. Da dies keine eigene Operation ist, muss sie mit einer der oben beschriebenen Operation per Oder (also mit einem einzelnen senkrechten Strich) verknüpft werden.

Die Funktion gibt im Erfolgsfall 0 ansonsten -1 zurück. Nähere Informationen finden Sie dann in der Variablen errno.

locking

Die Funktion locking wurde unter XENIX 3vgl. Rochkind, Marc J.: UNIX Programmierung für Fortgeschrittene. Hanser, München-Wien, 1988. S. 256-261. eingeführt.

int locking(int dateihandle, int kommando, long laenge);

Der Parameter kommando kann folgende Werte annehmen.

[Sperroperation bei locking]L|L Konstante & Bedeutung
LK_LOCK & Eine Sperre setzen
LK_UNLOCK & Eine Sperre aufheben

Die Sperre wird ab der aktuellen Dateiposition gesetzt. Als eigenen Parameter kennt locking nur die Länge des zu sperrenden Bereichs. Um die Dateiposition zu ändern, müssen Sie zuvor lseek() aufrufen.

advisory und mandatory

Es 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 wird das Set-Group-ID-Bit gesetzt und die Ausführbarkeit für die Gruppe gelöscht (siehe S. chmod). Eine solche Rechtevergabe ist an sich unsinnig, aber da zu sperrende Dateien Daten enthalten und keine ausführbaren Dateien sind, brauchen sie nicht ausführbar zu sein. Der Befehl, eine Datei namens datendatei auf mandantory locking umzustellen, lautet:

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.



« Dateieigenschaften ändern | Dateizugriffe | Link erzeugen: link, symlink »
 
 Zum Katalog
Zum Katalog
Wie werde ich UNIX-Guru?
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 UNIX/Linux

PHP 4-Workshop

Einstieg in Python

Perl fürs Web

MySQL 4

GNOME 2.0
 Empfehlung

Einstieg in XML
 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
Info

 MyGalileo
Der Service für registrierte Leser:
Zu MyGalileo
Info



Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de