Пасмо файл додається до файлу, через опис файлу . На високому рівні послідовність операцій в одному екземплярі сценарію:
- Відкрийте файл, до якого додається замок ("файл блокування").
- Візьміть замок у файлі блокування.
- Робіть речі.
- Закрийте файл блокування. Це звільняє замок, який додається до опису файлу, створеного відкриттям файлу.
Утримування блокування запобігає черговій копії того ж сценарію для запуску, тому що саме це роблять блоки. Поки ексклюзивний замок на файлі існує десь у системі, неможливо створити другий екземпляр того ж блокування навіть через інший опис файлу.
Відкриття файлу створює опис файлу . Це об’єкт ядра, який не має великої прямої видимості в інтерфейсах програмування. Ви отримуєте доступ до опису файлу опосередковано через дескриптори файлів, але зазвичай ви вважаєте, що це доступ до файлу (читання або запис його вмісту чи метаданих). Блокування - це один з атрибутів, які є властивістю опису файлу, а не файлу чи дескриптора.
На початку, коли файл відкривається, опис файлу має єдиний дескриптор файлу, але більше дескрипторів можна створити або шляхом створення іншого дескриптора ( dup
сімейство системних викликів), або шляхом розгортання підпроцесу (після чого і батьківський, і дитина має доступ до того ж опису файлу). Дескриптор файлу може бути закритий явно або тоді, коли процес, який він знаходиться, вмирає. Коли останній дескриптор файлу, приєднаний до файлу, закривається, опис файлу закривається.
Ось як послідовність операцій вище впливає на опис файлу.
- Перенаправлення
<$0
відкриває файл скрипту в підрозділі, створюючи опис файлу. На цьому етапі є один дескриптор файлу, приєднаний до опису: дескриптор номер 0 в нижній частині.
- Підрозділ викликає
flock
і чекає його виходу. Поки flock працює, до опису додаються два дескриптори: число 0 в нижній частині корпусу і число 0 в процесі flock. Коли flock бере блокування, воно встановлює властивість опису файлу. Якщо інший опис файлу вже має блокування у файлі, flock не може взяти замок, оскільки це ексклюзивний замок.
- Підрозділ робить речі. Оскільки в описі з блокуванням все ще є дескриптор відкритого файлу, він описується, і він зберігає його, оскільки його ніхто не знімає.
- Підшара відмирає при дужках, що закриваються. Це закриває останній дескриптор файлу в описі файлу, який має замок, тому замок зникає в цей момент.
Причина, з якої сценарій використовує переадресацію, $0
полягає в тому, що перенаправлення - єдиний спосіб відкрити файл в оболонці, а збереження активного перенаправлення - єдиний спосіб зберегти дескриптор файлу відкритим. Підрозділ ніколи не читає зі свого стандартного вводу, його просто потрібно тримати відкритим. Мовою, яка надає прямий доступ до відкритого та закритого дзвінка, ви можете використовувати
fd = open($0)
flock(fd, LOCK_EX)
do stuff
close(fd)
Насправді ви можете отримати ту саму послідовність операцій у оболонці, якщо виконати перенаправлення із exec
вбудованим.
exec <$0
flock -n -x 0
# do stuff
exec <&-
Сценарій може використовувати інший дескриптор файлу, якби він хотів продовжувати доступ до оригінального стандартного вводу.
exec 3<$0
flock -n -x 0
# do stuff
exec 3<&-
або з передплатою:
(
flock -n -x 3
# do stuff
) 3<$0
Блокування не повинно бути у файлі сценарію. Це може бути будь-який файл, який можна відкрити для читання (тому він повинен існувати, він повинен бути типом файлу, який можна читати, наприклад, звичайним файлом або іменованою трубкою, але не каталогом, і процес сценарію повинен мати дозвіл на його читання). Файл скрипту має ту перевагу, що він гарантовано присутній і читабельний (за винятком крайового випадку, коли він був видалений зовні між часом виклику сценарію та моментом надходження сценарію до <$0
переадресації).
Поки flock
успіх і сценарій знаходиться у файловій системі, де блокування не є помилковим (деякі мережеві файлові системи, такі як NFS, можуть бути помилковими), я не бачу, як використання іншого файлу блокування може дозволити перегони. Я підозрюю помилку маніпуляції з вашого боку.