Блокирование доступа к файлу
Блокирование доступа к файлу
Традиционно архитектура файловой подсистемы UNIX разрешает нескольким процессам одновременный доступ к файлу для чтения и записи. Хотя операции записи и чтения, осуществляемые с помощью системных вызовов read(2) или write(2), являются атомарными, в UNIX по умолчанию отсутствует синхронизация между отдельными вызовами. Другими словами, между двумя последовательными вызовами read(2) одного процесса другой процесс может модифицировать данные файла. Это, в частности, может привести к несогласованным операциям с файлом, и как следствие, к нарушению целостности его данных. Такая ситуация является неприемлемой для многих приложений.
UNIX позволяет обеспечить блокирование заданного диапазона байтов файла или записи файла. Для этого служат базовый системный вызов управления файлом fcntl(2) и библиотечная функция lockf(3C), предназначенная специально для управления блокированием. При этом перед фактической файловой операцией (чтения или записи) процесс устанавливает блокирование соответствующего типа (для чтения или для записи). Если блокирование завершилось успешно, это означает, что требуемая файловая операция не создаст конфликта или нарушения целостности данных, например, при одновременной записи в файл несколькими процессами.
По умолчанию блокирование является рекомендательным (advisory lock). Это означает, что кооперативно работающие процессы могут руководствоваться созданными блокировками, однако ядро не запрещает чтение или запись в заблокированный участок файла. При работе с рекомендательными блокировками процесс должен явно проверять их наличие с помощью тех же функций fcntl(2) и lockf(3C).
Мы уже встречались с использованием системного вызова fnctl(2) для блокирования записей файла в главе 2. Там же была упомянута структура flock, служащая для описания блокирования. Поля этой структуры описаны в табл. 4.8.
Таблица 4.8. Поля структуры flock
Поле Описание short l_type Тип блокирования: F_RDLCK обозначает блокирование для чтения (read lock), F_WRLCK — блокирование для записи (write lock), F_UNLCK обозначает снятие блокирования. short l_whence Точка отсчета смещения записи в файле. Может принимать значения, аналогичные рассмотренным при разговоре о функции lseek(2) в главе 2: SEEK_SET, SEEK_CUR, SEEK_END. off_t l_start Смещение блокируемой записи относительно точки отсчета, указанной полем l_whence. off_t l_len Длина блокируемой записи. Нулевое значение l_len указывает, что запись всегда распространяется до конца файла, независимо от возможного изменения его размера. pid_t l_pid Идентификатор процесса, установившего блокирование, возвращаемый при вызове команды GETLK.Как следует из описания поля l_type структуры flock, существуют два типа блокирования записи: для чтения (F_RDLCK) и для записи (F_WRLCK). Правила блокирования таковы, что может быть установлено несколько блокирований для чтения на конкретный байт файла, при этом в установке блокирования для записи на этот байт будет отказано. Напротив, блокирование для записи на конкретный байт должно быть единственным, при этом в установке блокирования для чтения будет отказано.
Приведем фрагмент программы, использующей возможность блокирования записей:
...
struct flock lock;
...
/* Заполним описание lock с целью блокирования всего файла
для записи */
lock.l_type = FWRLCK;
lock.l_start = 0;
lock.whence = SEEK_SET;
lock.len = 0;
/* Заблокируем файл. Если блокирования, препятствующие
данной операции, уже существуют — ждем их снятия */
fcntl(fd, SETLKW, &lock);
/* Запишем данные в файл - нам никто не помешает */
write(fd, record, sizeof(record));
/* Снимем блокирование */
lock.l_type = F_UNLK;
fcntl(fd, SETLKW, &lock);
В отличие от рекомендательного в UNIX существует обязательное блокирование (mandatory lock), при котором ограничение на доступ к записям файла накладывается самим ядром. Реализация обязательных блокировок может быть различной. Например, в SCO UNIX (SVR3) снятие бита x для группы и установка бита SGID для группы приводит к тому, что блокировки, установленные fcntl(2) или lockf(3C), станут обязательными. UNIX SVR4 поддерживает установку блокирования отдельно для записи и для чтения, обеспечивая тем самым доступ для чтения многим, а для записи — только одному процессу. Эти установки также осуществляются с помощью системного вызова fcntl(2). Следует иметь в виду, что использование обязательного блокирования таит потенциальную опасность. Например, если процесс блокирует доступ к жизненно важному системному файлу и по каким-либо причинам теряет контроль, это может привести к аварийному останову операционной системы.
Данный текст является ознакомительным фрагментом.