2013-04-03 5 views
13

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

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

+3

Используйте '(O_CREAT | O_EXCL)', чтобы получить сообщение об ошибке, если файл уже существует. Когда вы получите сообщение об ошибке, вы проверяете 'errno', чтобы убедиться, что это так, потому что оно существует, а затем повторно открыть, но вы хотите его открыть, зная, что он уже существует. – jxh

+0

А потом что делать? Но что, если другой процесс откроет его после моего чека, но до того, как я снова откроюсь, я хочу? – Sergey

+0

Ваша проблема в вашем описании не уточняется полностью. Обновите свой вопрос с фактической проблемой, с которой вы сталкиваетесь. Покажите некоторый код и укажите, где что-то не происходит так, как вы ожидаете. – jxh

ответ

2

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

/* 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) вызов, а затем удалить Это.

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

+0

Чтобы сразиться с live-lock, я бы отступил на какой-то глобальный общий мьютекс после нескольких итераций. Но тогда решение становится тем, чего я надеялся избежать. – Sergey

+0

Я принимаю этот ответ, так как это ближе всего к тому, чего я хотел достичь. – Sergey

6

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); 
} 
+0

вы можете прояснить «попытку открытия снова без O_CREAT». Если я опустил O_CREAT из вашего кода, я останусь только с O_EXCL и приравняюсь к [this] (http://linux.die.net/man/2/open) «В общем, поведение O_EXCL не определено если он используется без O_CREAT ". – Sergey

+0

Если O_EXCL создает сбой, потому что EEXISTS, попробуйте снова без _'O_EXCL'_ и без _'O_CREAT'_! Обратите внимание, что когда у вас O_CREAT, 'open()' принимает 3 аргумента; третий - режим разрешений файлов (0644 или аналогичный). Вам также нужен один из O_RDONLY, O_WRONLY или O_RDWR (хотя их исключение эквивалентно O_RDONLY, но создание файла в режиме только для чтения является бессмысленным). –

+0

Я исправил сообщение, которое, надеюсь, выяснится. – suspectus

Смежные вопросы