logoor-weiss.gif
SQL Anywhere 10 Launch
claim.gif
Linux Magazin Linux User Easy Linux International Linux Community
      Anzeigen
Softwareentwickler München
Übersetzungsagentur
Free Classifieds Glasgow
Günstige Linux Bücher
Handy Shop


Server, Linux-Software, Hardware, Linux-Bücher
verkaufen & kaufen
Kleinanzeigen & Preisvergleich

Notebooks | Drucker | PC-Systeme
Automarkt | Münzen
Wohnmobile | Grafikkarten Branchenbuch

Hier kaufen Unternehmen
Akku
Arbeitsspeicher
Beamer
Computer
CPU
Druckerkabel
Drucker
DVD-Brenner
Firewall
Festplatte
Hardware
Grafikkarte
Monitor
Kopierpapier
Netzteil
Mainboard
Notebook
Motherboard
Router
Netzwerkkarte
Scanner
Software
Server
SUSE Linux
Switch
TFT Monitor
Tastatur
USB Kabel
Toner
Werkzeug

Ersatzakku APC Akku Compaq
BELKIN LIEBERT RBC5 RBC6
RBC7 RBC8 RBC9 Batteriekit
APC Batterie RBC11 RBC12 USV
RBC14 RBC22 USV Batterie APC
RBC23 RBC24 Batterietausch
RBC25 RBC27 RBC31 RBC43
RBC44 Smartcell RBC2 RBC4
SYBATT DP320-E SUDP6000i

Akku Pulsar Evolution 3000 MGE

APC Smart UPS kaufen SUA750i
SUA1500i SUA1500RMI2U
SUA2200RMI2U SUA3000RMI2U

BB Battery BP12-6 BP5-12
BP7-12 BP7.2-12 Bleiakku
BP12-12 HR9-6 HR5.5-12 Batterie
HR5.8-12 Batterie HR9-12 Akku

CSB Akku GP1270 GP12110 USV

ColdFusion Hosting Webhosting
Matratzen Lattenrost Matratze
Nussknacker Nutcracker


Erschienen im Linux-Magazin 02/1999

Systemprogrammierung - Teil 8

Shared Memory

von Wolfgang Hetzler


Systemprogrammierung gilt als schwierig, da ihre Inhalte dem Beutzer sehr oft abstrakt gegenüber treten im Gegensatz zu praktischen Aufgabenstellungen, deren Sinn plastisch vor Augen steht. Daß diese Abstraktheit nicht sein muß und die Systemcalls eine wohldefinierte Schnittstelle zum Kernel darstellen, will diese Serie zeigen. Diesmal geht es um Shared Memory.

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.




Druckerfreundliche Version | Feedback zu dieser Seite | © 2006 Linux New Media AG | Last modified: 2005-07-28 23:21

Partner-Sites: [LinuxUser] [EasyLinux] [Linux-Community] [Linux Events] [OpenBytes] [Linux Magazine] [Linux Magazin Romania] [Linux Magazine Poland] [Linux Magazine Brasil] [Linux Magazine Spain]