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 memoriashmctl
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
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