Use shmget para alocar memória compartilhada em C
Este artigo irá demonstrar vários métodos sobre como usar a função shmget
para alocar memória compartilhada em C.
Use shmget
para alocar memória compartilhada em C
A memória compartilhada é uma das formas de comunicação entre processos que permite que dois ou mais processos troquem dados e se comuniquem rapidamente no espaço do usuário. A memória compartilhada implica que vários processos compartilham a mesma região na memória e eles podem modificar / acessar este segmento conforme necessário.
A interface que demonstraremos nos exemplos a seguir é chamada de memória compartilhada do System V, que é fornecida usando quatro funções: shmget
, shmat
, shmdt
e shmctl
.
shmget
é usado para criar um novo segmento de memória compartilhada ou recuperar um identificador para o segmento de memória já criado.- a chamada
shmat
é usada para anexar o segmento de memória compartilhada dado ao espaço de memória do processo de chamada. shmdt
pode ser empregado para separar o segmento de memória dadoshmctl
é usado para modificar e desalocar o segmento com várias opções.
O próximo exemplo de código implementa um uso básico das funções shmget
e shmat
para um processo que cria um novo segmento compartilhado e, em seguida, escreve alguns textos nele. A função shmget
leva três argumentos, o primeiro dos quais é a chave do segmento de memória. O valor da chave pode ser a macro IPC_PRIVATE
se o novo segmento precisar ser criado ou o valor da chave do segmento existente quando o identificador de memória deve ser obtido com a chamada. O segundo argumento de shmget
especifica o tamanho do segmento e o terceiro argumento são os sinalizadores de permissão que podem ser OR-editados para incluir vários valores.
Uma vez que o segmento de memória é criado, o identificador de segmento é obtido e pode ser passado para a função shmat
para anexar a memória fornecida. O usuário pode passar o endereço específico onde anexar o segmento de memória fornecido como um segundo argumento para shmat
. Ainda assim, normalmente, é preferível deixar o kernel escolher o endereço e especificar NULL
para denotar isso.
#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);
}
Resultado:
Segment ID 1540195
Attached at 0x7f6ba1437000
Hello there!
Uma vez que a função shmat
retorna o ponteiro válido, podemos tratá-lo como qualquer endereço de memória e operar nele conforme necessário. Finalmente, as funções shmdt
e shmctl
são chamadas para separar o segmento fornecido e desalocar a memória. Suponha que shmctl
não seja chamado em segmentos de memória alocados. Nesse caso, eles permanecem na memória do sistema depois que o programa termina, e pode atingir o limite de todo o sistema no segmento de memória compartilhada total.
Por outro lado, o próximo código de amostra demonstra como dois processos podem interagir usando a memória compartilhada. O código é o mesmo do exemplo anterior, exceto que depois de imprimir a string "Hello there!"
, O processo principal é bifurcado e um filho é criado, que armazena uma string diferente no mesmo endereço. Enquanto isso, o processo pai é suspenso, espera que o filho seja encerrado e sai com o código de sucesso; a string recém-armazenada é impressa no console. Se vários processos precisarem modificar e acessar segmentos de memória compartilhada simultaneamente, o programador precisará empregar algumas ferramentas de sincronização, como semáforos.
#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);
}
Resultado:
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