在Mac OS X上,ftruncate无法在POSIX共享内存上工作

11

我在 Mac OS X 上编写了以下代码,使用 POSIX 共享内存:

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    int fileHandle = shm_open("TW_ShMem1",O_CREAT|O_RDWR, 0666);

    if(fileHandle==-1) {
       //error.

    } else {
        //Here, it is failing on Mac OS X
        if(-1==ftruncate(fileHandle, 8192)) {
            shm_unlink("TW_ShMem1");
            fileHandle = -1;
        } else {
            return 0;
        }
    }

    return 1;
}

在Linux上,ftruncate正常工作。在Mac OS X上,它返回-1,并且errnoEINVAL(通过调试器查看)。

为什么会失败?这里漏掉了什么?


OS X的ftruncate手册声称,如果它是一个套接字而不是文件,它没有打开写入权限或长度参数小于零,它只会失败并返回EINVAL。那么,p_size的值是多少?如果您打开并截断常规文件,然后使用mmap,是否会发生同样的情况? - Useless
你能提供一个自包含的可编译示例吗? - Useless
memoryName 是 "TW9_Shm1",大小为 8192。 - doptimusprime
它在Linux上可以运行,但在Mac OS X上无法运行。它在ftruncate处失败了。 - doptimusprime
@Useless:看一下修改版。它应该有所帮助。在Mac OS X和Linux上必须能够编译通过,没有任何问题。 - doptimusprime
显示剩余2条评论
1个回答

12
这看起来像是OSX的行为 - ftruncate只在初始创建段时有效。任何后续调用都会失败。我能找到的最早的参考是一篇发表在苹果邮件列表中的帖子。
如果我在shm_open之前放置一个shm_unlink,那么ftruncate将始终有效。
假设您只想调整共享内存段的大小一次,则可以将ftruncate包装在fstat中以确定当前大小,并在st_size == 0的情况下调整其大小。
例如。
struct stat mapstat;
if (-1 != fstat(fileHandle, &mapstat) && mapstat.st_size == 0) {
    ftruncate(fileHandle, 8192);
}

请注意,如果此代码在不同的线程或进程中运行,可能会引入竞争条件。 - heiner
OSX内核代码中的共享内存区域说:“每个共享内存区域只能执行一次”(https://github.com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/bsd/kern/posix_shm.c#L525)。唯一的竞争是如果您选择了不同的大小。您仍然面临相同的限制-一生中只能截断一次。 - Anya Shenanigans
抱歉,我指的是fstat检查可能在不同的进程中引发。当然,如果忽略ftruncate的返回值,它仍然可以工作,但是fstat检查就不是必需的了。 - heiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接