открыть с O_CREAT - было ли оно открыто или создано?

У меня есть 10 процессов, которые пытаются открыть один и тот же файл более или менее одновременно с помощью открытого (O_CREAT) вызова, а затем удалить его. Есть ли какой-либо надежный способ узнать, какой процесс фактически создал файл и который уже открыл файл, например, если я хочу точно подсчитать, сколько раз этот файл был открыт в таком сценарии.

Я предполагаю, что могу поместить глобальный мьютекс в открытую операцию файла и выполнить последовательность вызовов open() с использованием флагов O_CREAT и O_EXCL, но это не соответствует моему определению "надежный".

Ответ 1

Основываясь на ваших комментариях, вы хотите что-то по строкам этой функции:

/* 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 процессов, которые пытаются открыть один и тот же файл более или менее одновременно с помощью открытого (O_CREAT) вызова, а затем удалить его.

Хак-иш, но более пуленепробиваемым решением было бы дать каждому процессу другой идентификатор пользователя. Затем просто используйте обычный open(path, O_CREAT|...) вызов. Затем вы можете запросить файл с помощью fstat() в файловом дескрипторе и проверить поле st_uid структуры stat. Если поле равно идентификатору пользователя процессов, то это был создатель. В противном случае это был нож. Это работает, так как каждый процесс удаляет файл после открытия.

Ответ 2

Используйте 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);
}