Axel Rogat
Betriebssysteme und betriebssystemnahes Programmieren
 
9.5: Shared Memory Kapitel 9 9.7: Sockets 
 
  9.6 Dateisperren  
 

Um Inkonsistenzen in gemeinsam benutzten Dateien (z.B. bei Datenbank-ähnlichen Anwendungen) zu vermeiden, gibt es einen POSIX-Mechanismus namens Record Locking. Auf diese Weise läßt sich der Einsatz von Semaphoren vermeiden (so denn welche zur Verfügung stehen), Blockade-Situationen müssen aber von den Prozessen selbst gemeistert werden.

Ein Record Lock ist eine Blockierung für einen beliebigen zusammenhängenden Teil einer Datei, ggf. natürlich auch einer ganzen Datei.

Es gibt zwei Arten von Locks ("Sperren"), "shared" und "exclusive". Solange auf ein Dateistück ein exklusives Lock existiert, kann es nicht ein zweites Mal gelockt werden. Lock-Bereiche dürfen einander überlappen. Wenn ein Byte Teil eines exklusiv gelockten Bereichs ist, ist dieses Lock das einzige.

Record Locking kann mit einem speziellen fcntl-Aufruf erfolgen:

UNIX
int fcntl(int fd, F_GETLK, struct flock *flp);
  Anfrage, ob das durch flp angegebene Lock durch ein bereits bestehendes verhindert würde. Wenn nicht, wird l_type auf F_UNLCK gesetzt, ansonsten wird flp mit den Daten des bestehenden Locks gefüllt.
int fcntl(int fd, F_SETLK, struct flock *flp);
  Einrichten eines Locks, das durch flp definiert wird (oder bei l_type=F_UNLK Aufheben eines bestehenden Locks). Wenn bereits ein exklusives Lock auf den Bereich besteht, kehrt die Funktion mit -1 zurück.
int fcntl(int fd, F_SETLKW, struct flock *flp);
  wie F_SETLK, aber blockierend (`W'=wait): Wenn bereits ein exklusiver Lock auf den Bereich besteht, wartet die Funktion, bis dieser aufgehoben wird.

Die verwendete Struktur flock hat folgenden Aufbau:

struct flock { short l_type; // Typ: F_RDLCK (shared), F_WRLCK (excl.), F_UNLCK short l_whence; // wie bei lseek: SEEK_SET, SEEK_CUR, SEEK_END off_t l_start; // Offset relativ zu whence off_t l_len; // Länge in Bytes, 0 bedeutet bis Dateiende pid_t l_pid; // wird von F_GETLK eingetragen };

Beispiel: Das folgende simple Programm kann nur in einer Instanz gleichzeitig laufen. Es lockt mit F_SETLK eine (existierende) Datei vollständig und exklusiv und wartet dann auf ein Signal. Ein zweiter Aufruf erhält dann keinen Lock mehr, fragt mit F_GETLCK genauer nach und gibt die PID des blockierenden Prozesses aus:

int main(int argc, char *argv[]) { struct flock flbuf; int fd=open("lockme",O_RDWR); if (fd<0) { perror("lockme"); exit(0); }

flbuf.l_type=F_WRLCK; flbuf.l_whence=SEEK_SET; flbuf.l_start=flbuf.l_len=0;

if (fcntl(fd,F_SETLK,&flbuf)) { fcntl(fd,F_GETLK,&flbuf); printf("schon gelockt von pid %d!\n",flbuf.l_pid); } else pause();

close(fd); }

 
9.5: Shared Memory Startseite 9.7: Sockets