Use shmget para alocar memória compartilhada em C

Jinku Hu 12 outubro 2023
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 dado
  • shmctl é 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
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

Artigo relacionado - C Memory