提问人:entonces 提问时间:10/19/2023 更新时间:10/19/2023 访问量:44
当我将偏移量更改为任何非零值时,在 C 中映射共享内存时出现无效参数错误
Mmapping shared memory in C giving Invalid argument error when I change the offset to anything nonzero
问:
我正在尝试打开一个共享内存文件,写入其中,分叉到新进程,然后调用 execl 运行其他组件,然后在这些组件中我想访问在父组件中创建的共享内存。但我不想要整个结构,只想要其中的一部分。因此,我使用 offsetof 来查找偏移量并将其传递给 mmap。问题是,当我将偏移量更改为零以外的任何值时,它会给出无效参数错误。它在零的情况下工作正常。
我做了一个最小的虚拟程序,有同样的错误,而大程序的代码太大了。 `
#include<stdio.h>
#include<unistd.h>
#include<sys/mman.h>
#include<stddef.h>
#include<fcntl.h>
typedef struct test
{
int moo;
char hello;
}Lil;
typedef struct bigstruct
{
int a;
char cow;
Lil lil;
}Big;
int main()
{
int fd = shm_open("/moomor", O_CREAT | O_RDWR, 0666);
if(fd == -1)
{
perror("shmopen");
return 1;
}
ftruncate(fd, sizeof(Big));
Big * big = (Big *)mmap(NULL, sizeof(Big), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(big == MAP_FAILED)
{
perror("mmap");
return 1;
}
big->lil.hello = 'h';
printf("hello: %c\n", big->lil.hello); //prints correctly
munmap(big, sizeof(Big)); //tried it with this in and out
int offset = offsetof(Big, lil); //gives offset of eight
printf("Offset: %d\n", offset);
Lil *lily = (Lil *)mmap(NULL, sizeof(Lil), PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
if(lily == MAP_FAILED)
{
perror("mmap"); //this causes an error
goto cleanup;
}
printf("HH: %c\n", lily->hello);
munmap(lily, sizeof(Lil));
cleanup:
shm_unlink("/moomor");
close(fd);
}
答:
2赞
Andreas Wenzel
10/19/2023
#1
假设您使用的是基于 Linux 的平台,函数 mmap
的手册页声明如下:
offset 必须是 sysconf(_SC_PAGE_SIZE) 返回的页面大小的倍数。
您似乎在发布的代码中违反了此规则。
评论
0赞
entonces
10/19/2023
非常感谢!我同意这似乎是问题所在,为了解决这个问题,我假设我会得到我想要的结构的偏移量。然后找到最近的页面对齐倍数并将余数传递到子进程中,获取指向该特定页面的 void 指针,然后使用偏移量获取特定结构?
0赞
Andreas Wenzel
10/19/2023
@entonces:找到“最近”的页面对齐倍数对我来说似乎是错误的。我宁愿猜测您可能希望找到“下一个较低”的页面对齐倍数,以便映射的内存范围包含您想要的所有数据。此外,数据可能跨越多个页面,因此我认为您不会想要使用“特定页面”。
0赞
entonces
10/19/2023
是的,接下来是我的意思,对不起。如果数据跨越多个页面,那不应该是问题,对吧?我已经实现了它,到目前为止它有效,谢谢。
1赞
Andreas Wenzel
10/19/2023
@entonces:是的,这应该不是问题。我的观点是,使用单个页面可能还不够。例如,如果数据恰好位于页面边界上,则即使数据的大小明显小于页面,它也可能跨越多个页面。
评论