【发布时间】:2021-06-24 10:44:26
【问题描述】:
我正在尝试将ftruncate 共享内存对象设置为特定长度。例如,我想使用以下 sn-p 将其长度设置为 1 个字节:
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
struct stat fd_stat;
int fd;
fd = shm_open("NAME", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
fstat(fd, &fd_stat);
printf("Size before: %lld\n", fd_stat.st_size);
ftruncate(fd, 1);
fstat(fd, &fd_stat);
printf("Size after: %lld\n", fd_stat.st_size);
}
在 Ubuntu 20.04 中打印:
Size before: 0
Size after: 1
这是我期望的输出。
但是,在 macOS X Big Sur 中,我得到:
Size before: 0
Size after: 4096
如您所见,它似乎正在将大小扩大到页面大小。
ftruncateLinux man page 内容如下:
truncate() 和 ftruncate() 函数会导致由 path 命名或由 fd 引用的常规文件被截断为 length 个字节。。 p>
尽管如此,POSIX specification 并不具体(双关语):
如果 fildes 引用常规文件,则 ftruncate() 函数将导致文件的大小截断为长度。 [...] 如果之前的文件小于这个大小,ftruncate() 将增加文件的大小。
这是否意味着ftruncate 总是将长度设置为完全指定的字节数?如果确实如此,这将意味着 macOS X Big Sur 不完全符合 POSIX(即使它被证明是这样)。如果没有,我如何保证它将fd 截断为我想要的大小?
【问题讨论】:
-
从表面上看,macOS 的行为似乎有所不同。有没有检查调用是否失败,
errno是否表示什么? -
共享内存对象不是常规文件。规范谈论常规文件。对于共享内存对象来说,一页(4 KiB)似乎并不合理。
-
SHM 上的 ftruncate 实际上在 POSIX 中是可选的,即使这样 it only says: "如果 ftruncate() 的效果是减小内存映射文件或共享内存对象的大小并且新端之外的整个页面先前已映射,那么新端之外的整个页面将被丢弃。”。 这是您在 macOS 上观察到的。所以 macOS 并非不符合 POSIX。
-
您引用的 POSIX 规范部分以 “如果 fildes 引用常规文件” 开头。该引用的其余部分与您的问题无关,因为共享内存不是常规文件。
-
除了来自
fstat的不同返回值之外,您希望在长度为 1 的共享内存对象和长度为 4096 的共享内存对象之间观察到什么实际区别?底层硬件机制意味着映射、权限、共享,无论如何都只能通过页面粒度来控制。我认为这就是为什么您会遇到所有 XY 问题 cmets - 您似乎非常关心在其他人看来毫无意义的差异。
标签: c linux posix shared-memory