Операционная система UNIX. Руководство программиста

     

Блокировка файлов


Есть несколько способов блокировки файла. Конкретный выбор зависит, в частности, от того, как оставшаяся часть программы будет использовать блокировку. Нужно также учесть проблемы эффективности и мобильности программы. Далее будут описаны два метода: один использует системный вызов fcntl(2), другой - библиотечную функцию lockf(3C) (удовлетворяющую стандарту /usr/group).

Блокировка всего файла на самом деле является частным случаем блокировки сегмента, поскольку и концепция, и результат блокировки одинаковы. Файл блокируется начиная с байта со смещением ноль и кончая максимально возможным размером файла, что нужно для предотвращения блокировок каких-либо сегментов файла. В этом случае значение длины блокировки устанавливается в ноль. Далее приведен фрагмент исходного текста, использующего для достижения цели системный вызов fcntl(2):

#include <fcntl.h> . . . #define MAX_TRY 10 int try; struct flock lck;

try = 0;

/* Заполним структуру, нужную для блокировки сегмента. Адрес структуры передается системному вызову fcntl */

lck.l_type = F_WRLCK; /* Блокировка на запись */ lck.l_whence = 0; /* Смещение от начала будет равно l_start */ lck.l_start = 0L; /* Блокировка от начала файла */ lck.l_len = 0L; /* и до конца */

/* Делаем не более MAX_TRY попыток блокировки */

while (fcntl (fd, F_SETLK, &lck) < 0) { if (errno == EAGAIN errno == EACCES) { /* Могут быть и другие ошибки, при которых надо повторить попытку */ if (++try < MAX_TRY) { (void) sleep (2); continue; } (void) fprintf (stderr, "Файл занят\n"); return; } perror("fcntl"); exit(2); } . . .

Приведенная часть исходного текста пытается заблокировать файл. Попытки повторяются несколько раз до тех пор, пока не случится одно из событий:

  • Файл удалось заблокировать.
  • Возникла ошибка.
  • Попытки прекращены из-за того, что их количество превысило MAX_TRY.

Чтобы выполнить эту же задачу, используя функцию lockf(3C), исходный текст должен иметь следующий вид:

#include <unistd.h> #define MAX_TRY 10 int try; try = 0;


/* Устанавливаем указатель текущей позиции в начало файла */

lseek (fd, 0L, 0);

/* Делаем не более MAX_TRY попыток блокировки */

while (lockf (fd, F_TLOCK, 0L) < 0) { if (errno == EAGAIN errno == EACCES) { /* Могут быть и другие ошибки, при которых надо повторить попытку */ if (++try < MAX_TRY) { (void) sleep (2); continue; } (void) fprintf (stderr, "Файл занят\n"); return; } perror("lockf"); exit(2); } . . .

Надо заметить, что пример с использованием lockf(3C) выглядит проще, однако пример с fcntl(2) демонстрирует дополнительную гибкость. При использовании fcntl(2) можно установить тип блокировки и начало блокируемого сегмента просто путем присваивания нужных значений компонентам структуры. В случае lockf(3C) просто устанавливается блокировка на запись (монопольная); для того, чтобы указать начало блокируемого сегмента, нужен дополнительный системный вызов [lseek(2)].




Содержание раздела