用O_CREAT打开 - 是打开还是创建?

Ser*_*gey 14 c unix file

我有10个进程尝试使用open(O_CREAT)调用同时或多或少地打开同一个文件,然后删除它.是否有任何可靠的方法来确定哪个进程实际上创建了文件,哪个进程已经打开已创建文件,例如,如果我想准确计算在这种情况下打开该文件的次数.

我想我可以在文件打开操作上放置一个全局互斥,并使用O_CREAT和O_EXCL标志执行一系列open()调用,但这不符合我对"robust"的定义.

sus*_*tus 7

使用O_EXCL标志O_CREAT.如果文件存在且errno将设置为,则此操作将失败EEXIST.如果确实失败,则在没有O_CREAT和没有O_EXCL模式的情况下再次尝试打开

例如

int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
if ((fd == -1) && (EEXIST == errno))
{
    /* open the existing file with write flag */
    fd = open(path, O_WRONLY);
}
Run Code Online (Sandbox Code Playgroud)


jxh*_*jxh 4

大致根据您的评论,您想要类似于此功能的内容:

/* return the fd or negative on error (check errno);
   how is 1 if created, or 0 if opened */
int create_or_open (const char *path, int create_flags, int open_flags,
                    int *how) {
    int fd;
    create_flags |= (O_CREAT|O_EXCL);
    open_flags &= ~(O_CREAT|O_EXCL);
    for (;;) {
        *how = 1;
        fd = open(path, create_flags);
        if (fd >= 0) break;
        if (errno != EEXIST) break;
        *how = 0;
        fd = open(path, open_flags);
        if (fd >= 0) break;
        if (errno != ENOENT) break;
    }
    return fd;
}
Run Code Online (Sandbox Code Playgroud)

该解决方案并非防弹。在某些情况下(可能是符号链接?)可能会导致它永远循环。此外,它可能在某些并发场景下发生活锁。我将把解决此类问题作为练习。:-)


在您编辑的问题中,您提出:

我有 10 个进程尝试使用 open(O_CREAT) 调用或多或少地同时打开同一个文件,然后将其删除。

一种黑客式但更防弹的解决方案是为每个进程提供不同的用户 ID。然后,只需使用常规open(path, O_CREAT|...)呼叫即可。fstat()然后,您可以使用文件描述符查询文件,并检查结构st_uid的字段stat。如果该字段等于进程的用户 ID,则它是创建者。否则,这就是一场揭幕战。这是有效的,因为每个进程都会在打开文件后删除该文件。