O básico que todo mundo ignora
Escolha de área é o tipo de problema que você resolve uma vez e depois gasta horas explicando pra quem chega depois. Espaços públicos, no sentido técnico, são áreas de memória ou armazenamento compartilhado que processos diferentes podem acessar simultaneamente. No contexto de Linux/Unix, isso geralmente se refere a shared memory segments criados via shm_open() ou System V IPC. Em containers e orquestração, o termo também aparece pra descrever namespaces de rede ou volumes partagados entre pods. Não vou dar a definição de enciclopédia. Vou contar o que acontece quando isso dá errado no mundo real.
Entendendo de verdade o que é espaços públicos
A confusão comum é achar que espaço público é só uma API que você chama e pronto. A realidade é que existem três camadas completamente separadas que compartilham o mesmo nome casual: POSIX shared memory — objetos criados com shm_open(), mountados em /dev/shm. Tem nome, tem permissões de arquivo, tem semântica de truncate(). É o mais usado em aplicações C/C++ que precisam de latência ultrabaixa.
System V shared memory — key_t identificador, criado com ftok() + shmget(). Mais antigo, mais burocrático, ainda rodando em sistemas legados de banco e telecom. O problema aqui é que o cleanup depende do administrador, não do processo. Named pipes (FIFOs) e message queues — às vezes chamados informalmente de "espaços públicos" por desenvolvedores que não querem diferenciar. Não são memória compartilhada, mas servem ao mesmo propósito de comunicação interprocessos.
Se você tá entrando nisso pela primeira vez, comece pelo POSIX. É mais previsível, a debugging é mais direta, e a documentação não exige três capítulos de histórico. Dei de cara com um problema específico há uns dois anos num serviço de trading. Tinha um segmento shm_open() de 2GB que o produtor escrevia e o consumidor lia. O problema? O consumo de memória não estava sendo liberado corretamente quando o processo morria de forma não-graciosa. O segmento ficava órfão no /dev/shm e o próximo startup tentava attachar num objeto corrompido. O erro era silencioso: read() retornava dados velhos, o sistema continuava rodando, e ninguém percebia até o relatório de reconciliação bater errado.
A workaround que funcionou foi dupla: primeiro, um watchdog externo que fazia shm_unlink() de segmentos com mais de X horas sem acesso ativo (usei inotify no diretório /dev/shm pra rastrear). Segundo, no código do processo, adicionei um handshake com sequencia number no header do segmento — se o Consumer recebesse um número fora da ordem, descarta o buffer e reinicializa. Isso resolveu. Não é elegante, mas funciona.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Como implementar na prática
Vamos direto ao POSIX shm_open(). O fluxo básico é: Criar ou abrir o objeto: shm_open("/meu_segmento", O_CREAT | O_RDWR, 0666). Isso retorna um file descriptor.
Definir o tamanho: ftruncate(fd, size). Essencial. Se você pular, mmap vai falhar com EINVAL. Fazer o mapeamento: mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0). Agora você tem um ponteiro válido pra escrever e ler.
Fechar o fd: close(fd). O mmap permanece válido. Muita gente esquece isso e acha que o segmento some. Para remover: shm_unlink("/meu_segmento"). Isso só remove a entrada do namespace, não a memória em si enquanto houver processo mapeado.
Levanta um semaforo separado se precisar de sincronização. Shared memory sem sincronização é receita pra race condition. Use sem_init() com PSHARED != 0. O pitfall mais comum: esquecêr que o tamanho do mmap precisa ser múltiplo da página do sistema. Em x86_64, isso é 4KB. Se você pedir 1 byte, o kernel ainda alocará uma página inteira. Em segmentos grandes, isso não importa. Em muitos segmentos pequenos rodando juntos, a fragmentação de página soma e pode estourar o limite do /dev/shm mais rápido do que o esperado.
Outro detalhe que ninguém menciona: /dev/shm é tmpfs. Isso significa que ele usa memória RAM + swap. Se o sistema ficar sem memória, o kernel pode começar a swapout segmentos compartilhados, e a latência que você esperava ganhar desaparece completamente. Testei isso em produção e a diferença era de 50ns para 2ms por operação. Inaceitável para o caso de uso. Se o seu cenário envolve mais de dois processos ou precisa de tolerância a falhas, considere usar message queues POSIX (mq_open) no lugar. A sobrecarga é ligeiramente maior, mas a semântica de fila evita muitos problemas de consistência que aparecem com shared memory pura.