Verwenden von shmget zum Zuweisen von gemeinsamem Speicher in C

Jinku Hu 12 Oktober 2023
Verwenden von shmget zum Zuweisen von gemeinsamem Speicher in C

Dieser Artikel demonstriert mehrere Methoden zur Verwendung der Funktion shmget, um gemeinsamen Speicher in C zuzuweisen.

Verwenden von shmget zum Zuweisen von gemeinsam genutztem Speicher in C

Gemeinsamer Speicher ist eine der Möglichkeiten der Interprozesskommunikation, die es zwei oder mehr Prozessen erlaubt, Daten auszutauschen und schnell im User-Space zu kommunizieren. Shared Memory bedeutet, dass sich mehrere Prozesse denselben Bereich im Speicher teilen und dass sie auf dieses Segment nach Bedarf zugreifen und es verändern können.

Die Schnittstelle, die wir in den folgenden Beispielen demonstrieren werden, heißt System V Shared Memory und wird durch vier Funktionen bereitgestellt: shmget, shmat, shmdt und shmctl.

  • shmget wird verwendet, um ein neues gemeinsames Speichersegment zu erstellen oder eine Kennung für ein bereits erstelltes Speichersegment abzurufen.
  • Der Aufruf von shmat wird verwendet, um das angegebene gemeinsame Speichersegment an den Speicherbereich des aufrufenden Prozesses anzuhängen.
  • shmdt kann verwendet werden, um das gegebene Speichersegment wieder zu lösen
  • shmctl wird verwendet, um das Segment mit mehreren Optionen zu modifizieren und zu deallokieren.

Der nächste Beispielcode implementiert eine grundlegende Verwendung der Funktionen shmget und shmat für einen Prozess, der ein neues gemeinsames Segment erstellt und dann einige Texte in dieses Segment schreibt. Die Funktion shmget nimmt drei Argumente entgegen, von denen das erste der Schlüssel des Speichersegments ist. Der Schlüsselwert kann das Makro IPC_PRIVATE sein, wenn das neue Segment erstellt werden soll, oder der Schlüsselwert des vorhandenen Segments, wenn die Kennung des Speichers mit dem Aufruf erhalten werden soll. Das zweite Argument von shmget gibt die Größe des Segments an und das dritte Argument sind die Berechtigungsflags, die ODER-verknüpft werden können, um mehrere Werte aufzunehmen.

Sobald das Speichersegment erstellt ist, erhält man den Segmentbezeichner, der an die Funktion shmat übergeben werden kann, um den angegebenen Speicher anzuhängen. Der Benutzer kann die spezifische Adresse, an die das gegebene Speichersegment angehängt werden soll, als zweites Argument an shmat übergeben. Normalerweise ist es jedoch vorzuziehen, den Kernel die Adresse auswählen zu lassen und NULL anzugeben, um dies zu kennzeichnen.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wait.h>

enum { SEGMENT_SIZE = 0x6400 };

const char *data = "Hello there!";

int main(int argc, char *argv[]) {
  int status;
  int segment_id;

  segment_id = shmget(IPC_PRIVATE, SEGMENT_SIZE,
                      IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
  char *sh_mem = (char *)shmat(segment_id, NULL, 0);

  printf("Segment ID %d\n", segment_id);
  printf("Attached at %p\n", sh_mem);
  memmove(sh_mem, data, strlen(data) + 1);
  printf("%s\n", sh_mem);

  shmdt(sh_mem);
  shmctl(segment_id, IPC_RMID, 0);
  exit(EXIT_SUCCESS);
}

Ausgabe:

Segment ID 1540195
Attached at 0x7f6ba1437000
Hello there!

Sobald die Funktion shmat den gültigen Zeiger zurückgibt, können wir ihn wie eine beliebige Speicheradresse behandeln und nach Bedarf darauf operieren. Schließlich werden die Funktionen shmdt und shmctl aufgerufen, um das angegebene Segment zu lösen und den Speicher freizugeben. Angenommen, shmctl wird nicht auf zugewiesene Speichersegmente aufgerufen. In diesem Fall verbleiben sie im Speicher des Systems, nachdem das Programm beendet wurde, und es kann die systemweite Grenze für das gesamte gemeinsam genutzte Speichersegment erreichen.

Andererseits zeigt das nächste Codebeispiel, wie zwei Prozesse unter Verwendung des gemeinsamen Speichers interagieren können. Der Code ist derselbe wie im vorherigen Beispiel, außer dass nach der Ausgabe der Zeichenkette "Hello there!" der Hauptprozess gegabelt und ein Kindprozess erstellt wird, der eine andere Zeichenkette an der gleichen Adresse speichert. In der Zwischenzeit hält der Elternprozess an, wartet auf die Beendigung des Kindprozesses und beendet sich mit einem Erfolgscode; die neu gespeicherte Zeichenkette wird auf der Konsole ausgegeben. Wenn mehrere Prozesse gleichzeitig auf gemeinsame Speichersegmente zugreifen und diese verändern müssen, muss der Programmierer einige Synchronisationswerkzeuge wie Semaphoren verwenden.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wait.h>

enum { SEGMENT_SIZE = 0x6400 };

const char *data = "Hello there!";

int main(int argc, char *argv[]) {
  int status;
  int segment_id;

  segment_id = shmget(IPC_PRIVATE, SEGMENT_SIZE,
                      IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
  char *sh_mem = (char *)shmat(segment_id, 0, 0);

  printf("Segment ID %d\n", segment_id);
  printf("Attached at %p\n", sh_mem);
  memmove(sh_mem, data, strlen(data) + 1);
  printf("%s\n", sh_mem);

  pid_t child_pid = fork();
  if (child_pid == -1) perror("fork");

  if (child_pid == 0) {
    strcpy(sh_mem, "NEW DATA Stored by Child Process\0");

    printf("child pid - %d\n", getpid());
    exit(EXIT_SUCCESS);
  } else {
    pid_t ret = waitpid(child_pid, &status, WUNTRACED | WCONTINUED);
    if (ret == -1) perror("waitpid");

    if (WIFEXITED(status))
      printf("Child exited, status - %d\n", WEXITSTATUS(status));

    if (WEXITSTATUS(status) == 0) printf("%s\n", sh_mem);
  }

  shmdt(sh_mem);
  shmctl(segment_id, IPC_RMID, 0);
  exit(EXIT_SUCCESS);
}

Ausgabe:

Segment ID 1540195
Attached at 0x7fd825a25000
Hello there!
child pid - 27291
Child exited, status - 0
NEW DATA Stored by Child Process
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C Memory