如何将共享内存映射到不同进程中的同一地址?

How to map shared memory to the same address in different processes?

我正在尝试在不同进程之间共享一些数据,但我想在所有进程中使用相同的地址。 从我读过的内容来看,似乎这应该可以使用 mmap()MAP_FIXED 标志(或 MAP_FIXED_NOREPLACE)。 有些人建议创建一个共享块,然后将该内存块的地址广播给所有其他进程。 This comment is a good summary of the whole idea.

所以我尝试将其实现到 this example。有一个发送者和一个接收者。发送方将创建一个共享内存块。接收方尝试在同一地址分配该内存块。该地址也使用共享内存块传递。

问题是接收器无法将内存对象映射到所述地址。 我收到 EINVAL 错误。

是否可以做我正在尝试的事情?如果是这样,我在这个例子中做错了什么?

// header.h

#pragma once

#define SHM_DATA_ADDR "/bitarray-addr"
#define SHM_DATA "/bitarray-data"

#define NUM 3
#define SIZE (NUM * sizeof(int))
#define SIZE_ADDR (sizeof(void *))
// sender.c

#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>

int main() {
  // Open the shared memory object for read-only access
  // Set permissions
  int fd      = shm_open(SHM_DATA, O_CREAT | O_EXCL | O_RDWR, 0600);
  int fd_addr = shm_open(SHM_DATA_ADDR, O_CREAT | O_EXCL | O_RDWR, 0600);

  ftruncate(fd, SIZE);
  ftruncate(fd_addr, SIZE_ADDR);

  // Establish mapping between address space and memory object
  int RDWR = PROT_READ | PROT_WRITE;
  int *data        = (int *)mmap(0, SIZE, RDWR, MAP_SHARED, fd, 0);
  void **data_addr = (void **)mmap(0, SIZE_ADDR, RDWR, MAP_SHARED, fd_addr, 0);
  *data_addr = data;

  printf("%p\n", data);
  printf("%p\n", data_addr);
  printf("%p\n", *data_addr);

  // Unmap address space
  munmap(data_addr, SIZE);
  munmap(data, SIZE);

  // Close file descriptors
  close(fd_addr);
  close(fd);

  return EXIT_SUCCESS;
}
// receiver.c

#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <errno.h>

int main() {
  // Open the shared memory object for read-only access
  // Set permissions
  int fd      = shm_open(SHM_DATA, O_RDONLY, 0600);
  int fd_addr = shm_open(SHM_DATA_ADDR, O_RDONLY, 0600);

  ftruncate(fd, SIZE);
  ftruncate(fd_addr, SIZE_ADDR);

  // Establish mapping between address space and memory object
  void **data_addr = (void **)mmap(0, SIZE_ADDR, PROT_READ, MAP_SHARED, fd_addr, 0);
  int *data        = (int *)mmap(*data_addr, SIZE, PROT_READ, MAP_FIXED, fd, 0);

  printf("%p\n", data_addr);
  printf("%p\n", *data_addr);
  printf("%p\n", data); 

  // Unmap address space
  munmap(data_addr, SIZE_ADDR);
  munmap(data, SIZE);

  // Close file descriptors
  close(fd_addr);
  close(fd);

  // Destroy shared memory object
  shm_unlink(SHM_DATA_ADDR);
  shm_unlink(SHM_DATA);

  return EXIT_SUCCESS;
}

来自 mmap(2) man page,强调我的:

The flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file. This behavior is determined by including exactly one of the following values in flags: [MAP_SHARED, MAP_SHARED_VALIDATE, MAP_PRIVATE]

In addition, zero or more of the following values can be ORed in flags: [MAP_ANONYMOUS, MAP_FIXED, etc]

在您的接收者代码中,您有:

int *data        = (int *)mmap(*data_addr, SIZE, PROT_READ, MAP_FIXED, fd, 0);

不包括 MAP_SHAREDMAP_SHARED_VALIDATEMAP_PRIVATE 中的任何一个,因此出现错误。它甚至在 Errors 部分中明确说明:

EINVAL: flags contained none of MAP_PRIVATE, MAP_SHARED or MAP_SHARED_VALIDATE.

将其更改为MAP_SHARED | MAP_FIXED,它对我来说运行成功。