Блокування одночасного запису у файл без використання функції flock

Андрій Чорний

При роботі CGI-скриптів, здійснюють запис у
файли (а це більшість їх видів – лічильники. гостьові книги, форуми
і т.п.) можлива ситуація, коли два або більше одночасно
запущених "примірника" скрипта спробують одночасно записувати
свої дані у файл.

Як мінімум, це може призвести до втрати результатів роботи
одного з примірників скрипта, а як максимум – порушенням структури
файлу даних і неможливістю нормальної роботи скрипта до
втручання адміна.

Тому в CGI-скриптах приймають спеціальні заходи
з блокування одночасного використання файлів даних кількома
скриптами одночасно. У мові Perl, як і в багатьох мовах
програмування, є спеціальна функція "блокування" файлу flock.

Однак на практиці ця функція не працює в портах
Perl під Windows 9x. Відповідно, скрипти, що використовують цю
функцію, на мій погляд, не можуть вважатися крос-платформеними. Це
також ускладнює налагодження скриптів на машині під Windows перед
перносом їх на UNIX-хостинг.

Тим не менше, захист файлів від одночасного
використання можна організувати і "своїм шляхом", і це буде
працювати на всіх системах.

Пропонований тут метод заснований на використанні
тимчасового файлу із заздалегідь відомим ім'ям.

Суть методу проста – перед тим, як "зайняти" файл
даних, скрипт створює цей тимчасовий файл, а після звільнення –
видаляє. Таким чином, наявність цього тимчасового файлу означає, що
файл даних зайнятий. Інший примірник скрипта перед записом перевіряє
наявність тимчасового файлу і, якщо він є, чекає його видалення
першим примірником, і тільки потім починає роботу з файлом даних.

Ім'я для тимчасового файлу може бути будь-яким –
головне, щоб для блокування різних файлів даних різними скриптами
використовувалися різні імена.

Частковий Perl-коду, що реалізує такий захист, може
бути таким:


$ Lockfile = "data.tmp"; # Ім'я тимчасового файлу блокування
$ Count = 50; $ interval = 0.05; # Кількість спроб і інтервал між ними

if (-e $lockfile)
{
# Якщо тимчасовий файл є, чекаємо його видалення іншим процесом

while (($count>0)&&(-e $lockfile))
{
sleep $interval;
$count-=1;
};
};

if ($count==0){
# Тут розміщується код обробки непередбаченої помилки
};
open TF, "> $ lockfile"; # Створюємо тимчасовий файл
close TF;

#…
# Тут розміщується власне код роботи з файлом даних
#…

unlink $ lockfile; # Видаляємо тимчасовий файл

Ця ділянка скрипта перевіряє, чи існує
тимчасовий файл. Якщо він існує, то виробляється ($ count)
перевірок його існування через інтервали ($ interval) секунд
(Значення 50 і 0.05 можна замінити своїми, тому припускають, що час
($ Count * $ interval) більш ніж достатня, щоб інший процес
завершив роботу з файлом даних). Як тільки тимчасовий файл буде
видалений іншим процесом, відбудеться вихід з циклу; далі скрипт
створює свій тимчасовий файл, осущетсвлять роботу з файлом даних і
видаляє тимчасовий файл.

Якщо скрипт працює на запис з кількома
файлами даних, то для захисту кожного повинен бути, природно, свій
вищеописаний фрагмент коду (у потрібному місці) і своє ім'я для
тимчасового файлу.

У багатьох випадках має сенс "блокувати" файл
даних не тільки під час запису в нього, а під час всього циклу
"Читання-модифікація-запис". В іншому випадку дуже можлива
втрата результатів роботи одного з "екземплярів" скрипта.

На мій погляд, цей підхід не менш надійний, ніж
"Стандартний Perl-івський", але зате нормально працює і під Win9x,
і під UNIX-подібними системами. При розробці своїх CGI-скриптів я
віддаю перевагу цей метод. Зокрема, у моєму "Скрипти
для ведення логів та обліку відвідувань "описаним вище чином
блокується одночасне використання трьох використовуваних скриптом
файлів даних, і в процесі багаторічного використання мною цього
CGI-скрипта жодних ексцесів, пов'язаних саме з цим, не було.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*