Flock(): удаление заблокированного файла без условия гонки?
Я использую flock() для inter-process с именем mutexes (т.е. какой-то процесс может решить заблокировать "some_name", который реализуется путем блокировки файла с именем "some_name" в каталоге temp:
lockfile = "/tmp/some_name.lock";
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);
do_something();
unlink(lockfile);
flock(fd, LOCK_UN);
Файл блокировки должен быть удален в какой-то момент, чтобы избежать заполнения каталога temp сотнями файлов.
Однако в этом коде есть очевидное условие гонки; пример с процессами A, B и C:
A opens file
A locks file
B opens file
A unlinks file
A unlocks file
B locks file (B holds a lock on the deleted file)
C opens file (a new file one is created)
C locks file (two processes hold the same named mutex !)
Есть ли способ удалить файл блокировки в какой-то момент без представления этого состояния гонки?
Ответы
Ответ 1
Извините, если я отвечу на мертвый вопрос:
После блокировки файла откройте другую копию, fstat обеих копий и проверьте номер inode, например:
lockfile = "/tmp/some_name.lock";
while(1) {
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);
fstat(fd, &st0);
stat(lockfile, &st1);
if(st0.st_ino == st1.st_ino) break;
close(fd);
}
do_something();
unlink(lockfile);
flock(fd, LOCK_UN);
Это предотвращает состояние гонки, потому что если в программе есть блокировка файла, который все еще находится в файловой системе, каждая другая программа, у которой есть оставшийся файл, будет иметь неправильный номер inode.
Я фактически доказал это в модели состояния-машины, используя следующие свойства:
Если P_i имеет дескриптор, заблокированный в файловой системе, тогда никакой другой процесс не находится в критическом разделе.
Если P_i после стата с правильным индексом или в критическом разделе, он имеет дескриптор, заблокированный в файловой системе.
Ответ 2
Если вы используете эти файлы только для блокировки и на самом деле не записываете их, я предлагаю вам рассматривать существование самой записи каталога как указание на удерживаемый замок и избегать использования flock
в целом.
Для этого вам необходимо создать операцию, которая создает запись в каталоге и сообщает об ошибке, если она уже существует. В Linux и в большинстве файловых систем для этого будет работать O_EXCL
до open
. Но некоторые платформы и некоторые файловые системы (в частности, более старые NFS) не поддерживают это. Поэтому справочная страница для open
предлагает альтернативу:
Портативные программы, которые хотят выполнять блокировку атомарного файла с использованием файла блокировки и должны избегать поддержки NFS для O_EXCL
, могут создавать уникальный файл в той же файловой системе (например, включая имя хоста и PID) и использовать link
(2), чтобы сделать ссылку на файл блокировки. Если link
(2) возвращает 0, блокировка будет успешной. В противном случае используйте stat
(2) в уникальном файле, чтобы проверить, увеличено ли его количество ссылок до 2, и в этом случае блокировка также успешный.
Таким образом, это выглядит как схема блокировки, которая официально задокументирована и, следовательно, указывает на определенный уровень поддержки и рекомендации по лучшей практике. Но я видел и другие подходы. bzr, например, использует каталоги вместо символических ссылок в большинстве мест. Цитата из его исходный код:
Блокировка представлена на диске каталогом определенного имени, содержащий файл информации. Выполнение блокировки осуществляется путем переименования временный каталог. Мы используем временные каталоги, потому что для всех известных транспортов и файловых систем мы считаем, что ровно один попытка заявить, что замок будет успешным, а остальные потерпят неудачу. (файлы не будет, потому что некоторые файловые системы или транспорты переименовать и перезаписать, что затрудняет определение того, кто выиграл.)
Один недостаток вышеприведенных подходов заключается в том, что они не будут блокироваться: неудачная попытка блокировки приведет к ошибке, но не дожидаться, пока блокировка станет доступной. Вам нужно будет опросить блокировку, что может быть проблематичным в свете споров о блокировке. В этом случае вам может потребоваться дальнейшее отступление от подхода на основе файловой системы и вместо этого использовать сторонние реализации. Но общие вопросы о том, как сделать ipc-мьютекс, уже заданы, поэтому я предлагаю вам искать [ipc] [mutex]
и посмотреть результаты, этот. Кстати, эти теги могут быть полезны и для вашего сообщения.