В Linux есть несколько механизмов блокировки файлов. Наиболее часто встречаются
flock() и fcntl().На первый взгляд они делают одно и то же: не дают нескольким процессам одновременно работать с одним файлом.
Но внутри ядра это разные механизмы, поэтому блокировки могут вообще не замечать друг друга.
▪️
flock блокирует сам файлПростейший вариант:
flock /tmp/app.lock -c 'echo "working"; sleep 10'
Пока первый процесс держит блокировку, второй:
flock -n /tmp/app.lock -c 'echo "working"'
получит ошибку и сразу завершится из-за
-n.Часто этот механизм используют для защиты cron-задач:
flock -n /run/myjob.lock /usr/local/bin/myjob
▪️
fcntl работает через диапазоны файлаЗдесь можно блокировать не только весь файл, но и конкретный диапазон байтов.
На уровне C:
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 100
};
fcntl(fd, F_SETLK, &lock);Можно заблокировать первые 100 байт, а другой процесс при этом сможет работать с другим диапазоном.
▪️Главная ловушка
Процесс A:
flock /tmp/test.lock
Процесс B использует
fcntl() для того же файла.Они не обязаны конфликтовать.
Причина в том, что
flock и традиционные POSIX advisory locks через fcntl исторически используют разные пространства блокировок.То есть наличие:
flock → locked
не означает автоматически:
fcntl → blocked
И наоборот.
▪️Обе блокировки advisory
Ни
flock, ни fcntl сами по себе не запрещают процессу открыть и изменить файл.Если приложение вообще не проверяет блокировку, оно может спокойно сделать:
echo "data" >> /tmp/file
Поэтому механизм работает только тогда, когда все участники системы договариваются его соблюдать.
▪️Есть ещё одна важная разница
Для
flock блокировка связана с открытым file description. При fork() дочерний процесс наследует соответствующую блокировку.У
fcntl семантика другая: POSIX locks связаны с процессом и имеют собственные правила поведения при close().Из-за этого без понимания модели владения FD легко получить ситуацию, когда один
close() неожиданно освобождает блокировку.▪️Практический вывод
Если нужно просто гарантировать, что cron или несколько экземпляров shell-скрипта не выполняются одновременно:
flock -n /run/myjob.lock /usr/local/bin/myjob
обычно достаточно.
Если приложение должно блокировать отдельные диапазоны файла или ему нужна POSIX-модель блокировок, используют
fcntl().И главное: нельзя считать
flock и fcntl взаимозаменяемыми только потому, что оба называются file locking.BashTex 📱 #bash #utils