Usa shmget per allocare la memoria condivisa in C

Jinku Hu 12 ottobre 2023
Usa shmget per allocare la memoria condivisa in C

Questo articolo mostrerà diversi metodi sull’utilizzo della funzione shmget per allocare la memoria condivisa in C.

Usa shmget per allocare la memoria condivisa in C

La memoria condivisa è uno dei modi di comunicazione tra processi che consente a due o più processi di scambiare dati e comunicare velocemente nello spazio utente. La memoria condivisa implica che più processi condividono la stessa regione in memoria e possono modificare / accedere a questo segmento secondo necessità.

L’interfaccia che mostreremo nei seguenti esempi è chiamata memoria condivisa di System V, fornita utilizzando quattro funzioni: shmget, shmat, shmdt e shmctl.

  • shmget viene utilizzato per creare un nuovo segmento di memoria condivisa o recuperare un identificatore per il segmento di memoria già creato.
  • La chiamata shmat è usata per allegare il dato segmento di memoria condivisa allo spazio di memoria del processo chiamante.
  • shmdt può essere impiegato per staccare il dato segmento di memoria
  • shmctl viene utilizzato per modificare e deallocare il segmento con più opzioni.

Il codice di esempio successivo implementa un utilizzo di base delle funzioni shmget e shmat per un processo che crea un nuovo segmento condiviso e quindi vi scrive dei testi. La funzione shmget accetta tre argomenti, il primo dei quali è la chiave del segmento di memoria. Il valore della chiave può essere la macro IPC_PRIVATE se il nuovo segmento deve essere creato o il valore della chiave del segmento esistente quando l’identificatore della memoria deve essere ottenuto con la chiamata. Il secondo argomento di shmget specifica la dimensione del segmento e il terzo argomento sono i flag di autorizzazione che possono essere modificati con OR per includere più valori.

Una volta creato il segmento di memoria, si ottiene l’identificativo del segmento, che può essere passato alla funzione shmat per allegare la memoria data. L’utente può passare l’indirizzo specifico a cui allegare il dato segmento di memoria come secondo argomento a shmat. Tuttavia, di solito, è preferibile lasciare che il kernel scelga l’indirizzo e specificare NULL per denotarlo.

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

Produzione:

Segment ID 1540195
Attached at 0x7f6ba1437000
Hello there!

Una volta che la funzione shmat restituisce il puntatore valido, possiamo trattarlo come qualsiasi indirizzo di memoria e operare su di esso secondo necessità. Infine, vengono chiamate le funzioni shmdt e shmctl per staccare il segmento dato e deallocare la memoria. Supponiamo che shmctl non venga chiamato sui segmenti di memoria allocati. In tal caso, rimangono nella memoria del sistema dopo che il programma è terminato e potrebbe raggiungere il limite a livello di sistema sul segmento di memoria condivisa totale.

D’altra parte, il codice di esempio successivo dimostra come due processi possono interagire utilizzando la memoria condivisa. Il codice è lo stesso dell’esempio precedente, tranne per il fatto che dopo aver stampato la stringa "Hello there!", Viene eseguito il fork del processo principale e viene creato un figlio, che memorizza una stringa diversa nello stesso indirizzo. Nel frattempo, il processo genitore si sospende, attende che il figlio termini ed esce con il codice di successo; la stringa appena memorizzata viene stampata sulla console. Se più processi devono modificare e accedere contemporaneamente a segmenti di memoria condivisa, il programmatore deve utilizzare alcuni strumenti di sincronizzazione come i semafori.

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

Produzione:

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

Articolo correlato - C Memory