![]() |
![]() |
||||||||||||||||||
![]() |
|
||||||||||||||||||
![]() |
|
||||||||||||||||||
|
Eine effiziente Variante, Nachrichten auszutauschen, bietet sicherlich gemeinsam benutzter Speicher, wenngleich das Synchronisationsproblem bei den beteiligten Prozessen liegt, die zusätzlich verbindungsorientiert arbeiten sollten. Der Gedanke hierzu ist einfach: Prozesse fordern zusätzlichen Speicher an, der über Zeiger referenziert wird, alle beteiligten Prozessen verfügen über diesen zusätzlichen Speicher - Shared Memory ist die Variante von Unix, die diese Strategie ermöglicht. Schauen wir uns zunächst die Prototypen der entsprechenden Systemcalls an (siehe Abb. 1):
Abb. 1: Die Shared Memory Systemaufrufe |
#include <sys/types.h> #include <ipc.h> #include <shm.h> int shmget (key_t key, int size, int shmflag); char * shmat (int shmid, char * shmaddr, int shmflag); int shmdt (char * shmaddr); int shmctl (int shmid, int cmd, struct shmid_ds buffer); |
Der Systemcall shmget liefert die ID der geinsamen Ressource, key spezifiziert den Schlüssel, size die gewünschte Größe und shmflag die Neuanlage und/oder den Zugriff. Ist key gleich IPC_PRIVATE wird kein Shared Memory Segment angelegt, ansonsten IPC_CREAT oder IPC_EXCL für die Fehlerbehandlung.
shmat liefert einen Zeiger auf das Shared Memory Segment, shmid ist die ID, die nach shmget von allen benutzt wird. Der Parameter shmaddr verweist auf die Adresszuweisung des Speichersegmentes, bei Angabe 0 wählt das System eine freie Region. Der letzte Parameter spezifiziert den Zugriff. Shmdt gibt den Zeiger auf das Shared Memory Segment, der als Parameter übergeben wird, wieder frei. Shmctl kann ähnlich wie msgctl interpretiert und mit cmd IPC_RMID zum Löschen des Segmentes herangezogen werden. Zur Demonstration betrachten wir eine kleine Client/Server-Anwendung (siehe Listing 1):
Listing 1: shmserver1.cpp |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY 100 main (int argc, char **argv) { char *sbuf, buf[512]; int sid; sid = shmget (KEY, 1024, 0666|IPC_CREAT); sbuf = shmat (sid,0,0); sprintf (sbuf, "hello world"); read (0, buf, 1); shmdt (sid); } |
Der Server legt mit shmget ein Segment in der Größe von 1024 Bytes mit read/write für alle an, KEY ist der symbolische Name. Mit shmat wird der Zeiger sbuf gesetzt und mit sprintf schließlich in das Segment geschrieben. Das read dient lediglich der Synchronisation und shmdt gibt den Zeiger frei. Wir betrachten nun den Client (siehe Listing 2):
Listing 2: shmclient1.cpp |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY 100 main(int argc, char **argv) { char *sbuf; int sid; sid = shmget (KEY, 1024, 0); sbuf = shmat (sid, 0, 0); printf ("%s", sbuf); shmdt (sid); } |
Mit shmget erwirbt der Client die ID und mit shmat setzt er den Pointer, der mit printf ausgelesen wird. Es ist klar ersichtlich, daß der Zugriff auf Shared Memory relativ einfach ist und bedingt durch den Zugriff über Pointer auf effizient. Es bleibt allerdings die Frage offen, wann hat der Server geschrieben und wann soll der Client lesen? Wir haben es hier mit einem allgemeinen Synchronisationsproblem zu tun. Wir nähern uns versuchsweise einer Lösung und führen dazu eine Ampel ein, die entweder auf Rot oder auf Grün steht. Wir benutzen dazu das erste Byte des gemeinsam genutzten Speichers und verbinden den Inhalt gleich 0 mit Rot und 1 mit Grün. Zunächst betrachten wir wieder die Server-Implementierung (siehe Listing 3):
Listing 3: sserver2.cpp |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY 100 main(int argc, char **argv) { char *sbuf, buf[512]; int sid; sid = shmget (KEY,1024,0666|IPC_CREAT); sbuf = shmat (sid, 0, 0); sprintf (sbuf+1, "hello world"); *sbuf = 1; read (0, buf, 1); shmdt (sid); shmctl (KEY, IPC_RMID, 0); } |
Nachdem die Nachricht "hello word" in den Shared-Memory Bereich übertragen worden ist, setzt der Server mit der Zeile
*sbuf = 1;
die Ampel auf Grün. Der restliche Source-Code ist in Analogie zum obigen Server zu interpretieren. Nachfolgend der Client (siehe Listing 4):
Listing 4: sclient2.cpp |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY 100 main(int argc, char **argv) { char *sbuf; int sid; sid = shmget (KEY, 1024, 0); sbuf = shmat (sid, 0, 0); while (!*sbuf); printf ("%s", sbuf); *sbuf = 0; shmdt (sid); } |
Die while-Schleife veranlaßt den Client zu warten bis das Byte den Wert 1 erhält. Nachdem die Nachricht verarbeitet worden ist, setzt der Client die "Ampel" wieder auf Rot. Dieser Rot/Grün - Mechanismus ermöglicht eine relativ einfache Synchronisation, die jedoch einige Probleme aufweist. Was passiert in einem ungünstigen Fall des Prozeßmanagements? Folgende Konstruktion ist denkbar: Der Server wird nach dem Senden der Nachricht unterbrochen, die "Ampel" wird nicht auf 1 gesetzt, der Client läuft in seiner while-Schleife weiter, wird unterbrochen und der Server schreibt die nächste Nachricht und setzt die "Ampel" auf Grün - eine Nachricht geht verloren. Ein weiteres Problem: Wie werden 1:n-Beziehungen effizient geregelt? Es ist leicht zu verstehen, daß unser Byte-Ampel keine gute Lösung impliziert - aber in einem ersten Ansatz funktioniert es und weckt das Problembewußtsein. Ich werde in der Folge über Semaphoren eine bessere Strategie vorstellen.
Infos |
[1] M. Beck, H. Böhme et al: Linux-Kernel-Programmierung, Addison-Wesley, 1997 [2] Rochkind: Unix-Programmierung für Fortgeschrittene, Hanser, 1985 [3] R. Bentson: Inside Linux, Seattle, SSC 1996 [4] Chris Brown: UNIX distributed programming, Prentice Hall [5] K.A. Robbins, Steven Robbins: Practical Unix Programming, Prentice Hall |
Der Autor |
Wolfgang Hetzler arbeitet seit 1985 als Dozent an einem privaten Institut für Fort- und Ausbildung im EDV-Bereich und als Lehrbeauftragter an der FH-Frankfurt im Bereich Ingenieur-Informatik. Linux ist ihm seit der Version 0.9xx bekannt und eine Quelle ständiger Auseinandersetzung. Zu erreichen ist er unter het@het.gg.eunet.de. |
Copyright © 1998 Linux-Magazin Verlag
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links" nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedruckten Fassung entsprechen.
Partner-Sites:
[LinuxUser]
[EasyLinux]
[Linux-Community]
[Linux Events]
[OpenBytes]
[Linux Magazine]
[Linux Magazin Romania]
[Linux Magazine Poland]
[Linux Magazine Brasil]
[Linux Magazine Spain]