SHMOP(2) | Linux-Programmierhandbuch | SHMOP(2) |
shmat, shmdt - System-V-Operationen mit gemeinsam benutztem Speicher
#include <sys/types.h> #include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
shmat() blendet das durch shmid bezeichnete gemeinsame System-V-Speichersegment in den Adressraum des aufrufenden Prozesses ein. Die Adresse der Einblendung wird durch shmaddr nach einem der folgenden Kriterien bestimmt:
Zusätzlich zu SHM_RND dürfen die folgenden Schalter im Bitmask-Argument von shmflg angegeben werden:
Der brk(2)-Wert des aufrufenden Prozesses wird durch das Einblenden nicht verändert. Das Segment wird bei Beenden des Prozesses automatisch abgetrennt. Das gleiche Segment kann mit Lese- sowie mit Lese- und Schreibzugriff einmal oder mehrfach in den Adressraum des Prozesses eingeblendet werden.
Nach einem erfolgreichen shmat()-Aufruf aktualisiert das System die Bestandteile der dem Speichersegment zugeordneten shmid_ds-Struktur (siehe shmctl(2)) wie folgt:
shmdt() löst das gemeinsame Speichersegment, das an der Adresse shmaddr liegt, aus dem Adressraum des aufrufenden Prozesses. Das zu entfernende gemeinsame Speichersegment muss momentan mit shmaddr eingeblendet sein, das dem Rückgabewert des einbendenden shat()-Aufrufs entspricht.
Nach einem erfolgreichen shmdt()-Aufruf aktualisiert das System die Bestandteile der dem Speichersegment zugeordneten Struktur shmid_ds wie folgt:
Bei Erfolg gibt shmat() die Adresse des eingeblendeten gemeinsamen Speichersegments zurück; bei einem Fehler wird (void *) -1 zurückgegeben und errno so gesetzt, dass es den Grund des Fehlers anzeigt.
Bei Erfolg gibt shmdt() 0 zurück; bei einem Fehler wird -1 zurückgegeben und errno so gesetzt, dass es den Grund des Fehlers anzeigt.
Wenn shmat() fehlschlägt, wird errno mit einem der folgenden Werte belegt:
Wenn shmdt() fehlschlägt, wird errno mit einem der folgenden Werte belegt:
POSIX.1-2001, POSIX.1-2008, SVr4.
In SVID 3 (oder vielleicht früher) wurde der Typ des Arguments shmaddr von char * in const void * und der von shmat() zurückgegebene Typ von char * in void * geändert.
Nach einem fork(2) erbt der Kindprozess das eingeblendete gemeinsame Speichersegment.
Nach einem exec(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelöst.
Bei einem exit(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelöst.
Die bevorzugte, portierbare Möglichkeit, ein gemeinsames Speichersegment einzublenden, besteht darin, shmat() mit shmaddr gleich NULL zu benutzen. Sie sollten wissen, dass das eingeblendete gemeinsame Speichersegment auf diese Art an unterschiedliche Adressen in unterschiedlichen Prozessen eingeblendet werden kann. Deshalb müssen alle innerhalb des gemeinsamen Speichers verwalteten Zeiger relativ (typischerweise zur Startadresse des Segments) statt absolut sein.
Unter Linux ist es möglich, sogar ein gemeinsames Speichersegment einzublenden, wenn es bereits zum Löschen markiert ist. POSIX.1 spezifiziert dieses Verhalten jedoch nicht und andere Implementierungen unterstützen es nicht.
Der folgende Systemparameter beeinflusst shmat():
Die Implementierung hat keine inhärenten pro-Prozess-Einschränkungen bezüglich der maximalen Anzahl von gemeinsamen Speichersegmenten (SHMSEG).
Die zwei nachfolgend aufgeführten Programme tauschen eine Zeichenkette über ein gemeinsames Speichersegment aus. Weitere Details über die Programme finden Sie nachfolgend. Zuerst wird eine Shell-Sitzung gezeigt, die ihre Verwendung zeigt.
In einem Terminalfenster führen wir das »Lese«-Programm aus, das ein gemeinsam benutztes Speichersegment und eine Semaphoren-Gruppe gemäß System-V erstellt. Das Programm gibt die Kennung der erstellten Objekte aus und wartet dann darauf, dass die Semaphore ihren Wert ändern.
$ ./svshm_string_read shmid = 1114194; semid = 15
In einem anderen Terminal-Fenster führen wir das »Schreibe«-Programm aus. Das »Schreibe«-Programm akzeptiert drei Befehlszeilenargumente: die Kennungen des vom »Lese«-Programm erstellten gemeinsam benutzten Speichersegments und die erstellte Semaphoren-Gruppe und eine Zeichenkette. Es blendet das bestehende gemeinsam benutzte Speichersegment ein, kopiert die Zeichenkette in den gemeinsam benutzten Speicher und verändert den Wert der Semaphore.
$ ./svshm_string_write 1114194 15 'Hallo, Welt'
In dem Terminal-Fenster, in dem das »Lese«-Programm läuft, können wir sehen, dass das Programm aufgehört hat, auf die Semaphore zu warten und die Zeichenkette ausgegeben hat, die vom Schreibe-Programm in den gemeinsam benutzten Speicher kopiert wurde:
Hallo Welt
Die folgenden Header-Datei wird von den »Lese«- und »Schreibe«-Programmen eingebunden:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define errExit(Nachricht) do { perror(Nachricht); exit(EXIT_FAILURE); \
} while (0) union semun { /* Wird in Aufrufen von semctl() verwandt */
int val;
struct semid_ds * buf;
unsigned short * array; #if defined(__linux__)
struct seminfo * __buf; #endif }; #define MEM_SIZE 4096
Das »Lese«-Programm erstellt ein gemeinsam benutztes Speichersegment und eine Semaphore-Gruppe, die eine Semaphore enthält. Es blendet dann das gemeinsam benutzte Speicherobjekt in seinen Adressraum ein und initialisiert den Semaphoren-Wert auf 1. Schließlich wartet das Programm darauf, dass der Semaphoren-Wert 0 wird und gibt danach die Zeichenkette aus, die durch den »Schreiber« in das gemeinsam benutzte Speichersegment kopiert wurde.
/* svshm_string_read.c
Lizenziert unter der GNU General Public License v2 oder neuer. */ #include "svshm_string.h" int main(int argc, char *argv[]) {
int semid, shmid;
union semun arg, dummy;
struct sembuf sop;
char *addr; int main(int argc, char *argv[]) {
struct stat sb;
char *buf;
ssize_t nbytes, bufsiz;
/* Gemeinsam benutzten Speicher und eine Semaphoren-Gruppe, die eine
Semaphore enthält, erstellen */
shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
if (shmid == -1)
errExit("shmget");
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
if (shmid == -1)
errExit("shmget");
/* Gemeinsamen Speicher in unseren Adressraum einblenden */
addr = shmat(shmid, NULL, SHM_RDONLY);
if (addr == (void *) -1)
errExit("shmat");
/* Semaphore 0 in der Gruppe mit dem Wert 1 initialisieren */
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1)
errExit("semctl");
printf("shmid = %d; semid = %d\n", shmid, semid);
/* Darauf warten, dass der Semaphore-Wert 0 wird */
sop.sem_num = 0;
sop.sem_op = 0;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
errExit("semop");
/* Die Zeichenkette aus dem gemeinsamen Speicher ausgeben */
printf("%s\n", addr);
/* Den gemeinsam benutzten Speicher und die Semaphoren-Gruppe entfernen */
if (shmctl(shmid, IPC_RMID, NULL) == -1)
errExit("shmctl");
if (semctl(semid, 0, IPC_RMID, dummy) == -1)
errExit("semctl");
exit(EXIT_SUCCESS); }
Das Schreibe-Programm akzeptiert drei Befehlszeilenargumente: die Kennungen des vom »Lese«-Programm bereits erstellten, gemeinsam benutzten Speichersegments und die Sempahoren-Gruppe und eine Zeichenkette. Es blendet das bestehende gemeinsam benutzte Speichersegment in seinen Adressraum ein, verringert den Semaphoren-Wert auf 0, um den »Leser« zu informieren, dass er jetzt den Inhalt des gemeinsam benutzten Speichers untersuchen kann.
/* svshm_string_write.c
Lizenziert unter der GNU General Public License v2 oder neuer. */ #include "svshm_string.h" int main(int argc, char *argv[]) {
int semid, shmid;
struct sembuf sop;
char *addr;
size_t len;
if (argc != 4) {
fprintf(stderr, "Aufruf: %s Shmid Semid Zeichenkette\n", argv[0]);
exit(EXIT_FAILURE);
}
len = strlen(argv[3]) + 1; /* +1, um abschließende '\0' einzuschließen */
if (len > MEM_SIZE) {
fprintf(stderr, "Zeichenkette ist zu groß!\n");
exit(EXIT_FAILURE);
}
/* Objektkennungen von der Befehlszeile erhalten */
shmid = atoi(argv[1]);
semid = atoi(argv[2]);
/* Gemeinsam benutzten Speicher in unseren Adressraum einblenden und Zeichenkette
(einschließlich abschließendem NULL-Byte) in den Speicher kopieren */
addr = shmat(shmid, NULL, 0);
if (addr == (void *) -1)
errExit("shmat");
memcpy(addr, argv[3], len);
/* Semaphore auf 0 verringern */
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
errExit("semop");
exit(EXIT_SUCCESS); }
brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
Diese Seite ist Teil der Veröffentlichung 5.10 des Projekts Linux-man-pages. Eine Beschreibung des Projekts, Informationen, wie Fehler gemeldet werden können sowie die aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.
Die deutsche Übersetzung dieser Handbuchseite wurde von Ralf Demmer <rdemmer@rdemmer.de>, Chris Leick <c.leick@vollbio.de> und Helge Kreutzmann <debian@helgefjell.de> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die Mailingliste der Übersetzer.
11. April 2020 | Linux |