gpt4 book ai didi

无法在 MacOS 上从 shm_open 写入 fd

转载 作者:行者123 更新时间:2023-12-05 03:18:21 26 4
gpt4 key购买 nike

我正在尝试写入然后从使用 shm_open 打开的文件描述符中读取。它在 Linux 上的工作方式与我预期的一样,但在 macOS(特别是 macOS Monterey 12.5 21G72)上却不行。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

int main(int argc, const char * argv[]) {
int fd = shm_open("/example", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if (fd < 0) {
printf("shm_open() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

const char *buf = "hello world";
unsigned long len = strlen(buf);

ssize_t ret = write(fd, buf, len);
if (ret < 0) {
printf("write() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

ret = lseek(fd, 0, SEEK_SET);
if (ret < 0) {
printf("lseek() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

char *newbuf = calloc(len + 1, 1);

ret = read(fd, newbuf, len);
if (ret < 0) {
printf("read() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

printf("read: %s\n", newbuf);
return 0;
}

在 Linux 上,输出是我所期望的:

$ cc main.c
$ ./a.out
read: hello world

在 macOS 上我得到这个:

$ cc main.c
$ ./a.out
write() failed Device not configured (6)

最佳答案

在 Linux 下,POSIX 共享内存通常由安装在 /dev/shm 上的 tmpfs 文件系统支持:

$ cat /proc/mounts | grep /dev/shm
tmpfs /dev/shm tmpfs rw,nosuid,nodev,inode64 0 0

传递给shm_open()的名称是共享内存区对应的文件入口的名称:

$ gcc main.c -lrt  
$ ./a.out
read: hello world
$ ls -l /dev/shm
total 4
-rw------- 1 xxx xxx 11 sept. 17 08:53 example

上述文件系统通常在启动时通过/etc/fstabsystemd 挂载。

在 MacOS 下,这个 manual表示共享内存段在文件系统中没有可见条目:

There is no visible entry in the file system for the created object in this implementation.

因此,底层实现与 Linux 中的不同。您可能只能通过添加对 ftruncate() 的调用来设置内存段的大小并使用 mmap() 将内容映射到进程地址空间,因为它是我们通常使用共享内存的方式。任何想要访问该区域的进程都会做同样的事情,除了只有一个应该指定 O_CREATshm_open() 并调用 ftruncate() 到创建/调整对象大小:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

int main(int argc, const char * argv[]) {

int flags = O_RDWR;

// Pass some parameter to trigger the creation of the object
if (argc > 1) {
flags |= O_CREAT;
}

int fd = shm_open("/example", flags, S_IRUSR|S_IWUSR);
if (fd < 0) {
printf("shm_open() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

const char *buf = "hello world";
unsigned long len = strlen(buf);

if (argc > 1) {

ssize_t ret = ftruncate(fd, len + 1);
if (ret < 0) {
printf("ftruncate() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

}

char *newbuf = (char *)mmap(NULL, len + 1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (newbuf == MAP_FAILED) {
printf("mmap() failed %s (%d)\n", strerror(errno), errno);
return 1;
}

if (argc > 1) {

memcpy(newbuf, buf, len + 1);

}

printf("read: %s\n", newbuf);
return 0;
}

Linux下执行示例:

$ gcc main.c -lrt
$ ls -l /dev/shm
total 0
$ ./a.out
shm_open() failed No such file or directory (2)
$ ls -l /dev/shm
total 0
$ ./a.out creat
read: hello world
$ ls -l /dev/shm
total 4
-rw------- 1 xxx xxx 12 sept. 17 09:36 example
$ ./a.out
read: hello world

附加信息

MacOS 源自 BSD . manual后者明确指定对生成的文件描述符的操作如 read()write() 返回错误:

The result of using open(2), read(2), or write(2) on a shared memory object, or on the descriptor returned by shm_open(), is undefined. It is also undefined whether the shared memory object itself, or its contents, persist across reboots.
In FreeBSD, read(2) and write(2) on a shared memory object will fail with EOPNOTSUPP and neither shared memory objects nor their contents persist across reboots.

关于无法在 MacOS 上从 shm_open 写入 fd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73752631/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com