2

我需要“伪造”一个文件描述符(支持fstat),我就是这样做的。

func ScanBytes(b []byte) error {
  size := C.size_t(len(b))
  path := C.CString("/bytes")
  fd := C.shm_open(path, C.O_RDWR|C.O_CREAT, C.mode_t(0600))
  defer C.shm_unlink(path)
  defer C.close(fd)

  res := C.ftruncate(fd, C.__off_t(size))
  if res != 0 {
    return fmt.Errorf("could not allocate shared memory region (%d)", res)
  }

  var addr = unsafe.Pointer(&b[0])
  C.mmap(addr, size, C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED|C.MAP_FIXED, fd, 0)
  defer C.munmap(addr, size)

  // _, err := syscall.Write(int(fd), b)

  return doSomethingWith(fd)
}

您会看到写入文件句柄的位置被注释掉了。

如果我不将缓冲区写入分配的区域,则它是空的。我希望mmap结合MAP_FIXED使用提供的缓冲区的地址,从而将内容映射到该区域。

我猜write调用副本,从而使内存使用量加倍。我真的必须write吗?

4

1 回答 1

3

听起来您想要的是能够通过文件描述符访问现有内存区域而无需复制。

这个问题听起来很像之前关于 mmap 的 stackoverflow 问题

那里的答案没有什么可补充的。鉴于您不控制b. 接受需要副本,您的 shm 解决方案很好。不需要 mmap。

从 mmap 的手册页中,定义MAP_FIXED

不允许系统选择与指定地址不同的地址。如果无法使用指定的地址,mmap() 将失败。如果指定了 MAP_FIXED,则 addr 必须是页面大小的倍数。如果 MAP_FIXED 请求成功,则 mmap() 建立的映射将替换从 addr 到 addr + len 范围内进程页面的任何先前映射。不鼓励使用此选项。

这很可能unsafe.Pointer(&b[0])不是页面大小的倍数,尤其是在底层数组很小的情况下。在这种情况下 mmap 会失败。与往常一样,检查返回值

如果 mmap 成功,映射将替换任何以前的映射,这意味着您的数据现在已经消失了。读取切片将为您提供零字节。

于 2013-11-26T17:06:15.333 回答