15

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

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

4

2 回答 2

8

O_EXCL标志与O_CREAT. 如果文件存在并且 errno 将设置为 ,这将失败EEXISTO_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);
}
于 2013-04-03T21:30:10.737 回答
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;
}

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


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

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

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

于 2013-04-03T22:13:00.223 回答