Utilisez shmget pour allouer de la mémoire partagée en C

Jinku Hu 12 octobre 2023
Utilisez shmget pour allouer de la mémoire partagée en C

Cet article présente plusieurs méthodes d’utilisation de la fonction shmget pour allouer de la mémoire partagée en C.

Utilisez shmget pour allouer de la mémoire partagée en C

La mémoire partagée est l’un des moyens de communication interprocessus qui permet à deux processus ou plus d’échanger des données et de communiquer rapidement dans l’espace utilisateur. La mémoire partagée implique que plusieurs processus partagent la même région en mémoire et qu’ils peuvent modifier/accéder à ce segment si nécessaire.

L’interface que nous allons démontrer dans les exemples suivants est appelée mémoire partagée System V, qui est fournie à l’aide de quatre fonctions: shmget, shmat, shmdt et shmctl.

  • shmget est utilisé pour créer un nouveau segment de mémoire partagée ou récupérer un identifiant pour le segment de mémoire déjà créé.
  • L’appel shmat est utilisé pour attacher le segment de mémoire partagée donné à l’espace mémoire du processus appelant.
  • shmdt peut être utilisé pour détacher le segment de mémoire donné
  • shmctl est utilisé pour modifier et désallouer le segment avec plusieurs options.

L’exemple de code suivant implémente une utilisation basique des fonctions shmget et shmat pour un processus qui crée un nouveau segment partagé puis y écrit des textes. La fonction shmget prend trois arguments, dont le premier est la clé du segment de mémoire. La valeur de clé peut être la macro IPC_PRIVATE si le nouveau segment doit être créé ou la valeur de clé du segment existant lorsque l’identifiant de mémoire doit être obtenu avec l’appel. Le deuxième argument de shmget spécifie la taille du segment et le troisième argument est les indicateurs d’autorisation qui peuvent être modifiés par OU pour inclure plusieurs valeurs.

Une fois le segment de mémoire créé, l’identifiant de segment est obtenu, et il peut être passé à la fonction shmat pour attacher la mémoire donnée. L’utilisateur peut passer l’adresse spécifique où attacher le segment de mémoire donné comme deuxième argument à shmat. Pourtant, généralement, il est préférable de laisser le noyau choisir l’adresse et de spécifier NULL pour l’indiquer.

#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);
}

Production:

Segment ID 1540195
Attached at 0x7f6ba1437000
Hello there!

Une fois que la fonction shmat retourne le pointeur valide, nous pouvons le traiter comme n’importe quelle adresse mémoire et agir dessus si nécessaire. Enfin, les fonctions shmdt et shmctl sont appelées pour détacher le segment donné et désallouer la mémoire. Supposons que shmctl ne soit pas appelé sur des segments de mémoire alloués. Dans ce cas, ils restent dans la mémoire du système après la fin du programme et il peut atteindre la limite du système sur le segment total de la mémoire partagée.

D’autre part, l’exemple de code suivant montre comment deux processus peuvent interagir à l’aide de la mémoire partagée. Le code est le même que celui de l’exemple précédent, sauf qu’après avoir imprimé le "Hello there!" string, le processus principal est forké et un enfant est créé, qui stocke une chaîne différente dans la même adresse. Pendant ce temps, le processus parent se suspend, attend que l’enfant se termine et se termine avec un code de réussite; la chaîne nouvellement stockée est imprimée sur la console. Si plusieurs processus doivent modifier et accéder simultanément à des segments de mémoire partagée, le programmeur doit utiliser certains outils de synchronisation comme les sémaphores.

#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);
}

Production:

Segment ID 1540195
Attached at 0x7fd825a25000
Hello there!
child pid - 27291
Child exited, status - 0
NEW DATA Stored by Child Process
Auteur: 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

Article connexe - C Memory