. Эта команда получает информацию о файле, который открыт
fildes
(первый параметр в вызове). Она не пытается блокировать файл. В процессе вызова передаются сведения о типе блокировки, которую хотелось бы установить, и вызов
fcntl
с командой
F_GETLK
возвращает любую информацию, которая могла бы помешать установке блокировки.
Значения, используемые в структуре
flock
, приведены в табл. 7.2.
Таблица 7.2
Значение
Описание
l_type
Или
F_RDLCK
для разделяемой (только чтение) блокировки, или
F_WRLCK
для исключительной (на запись) блокировки
l_whence
Одно из значений:
SEEK_SET
,
SEEK_CUR
или
SEEK_END LCK
l_start
Начальный байт интересующего вас участка файла
l_len
Количество байтов в интересующем вас участке файла
l_pid
Идентификатор процесса, удерживающего блокировку
Процесс может применять вызов с командой
F_GETLK
для определения текущего состояния блокировки участка файла. Он должен настроить структуру
flock
, указав тип требуемой блокировки и определив интересующую его область файла. Вызов
fcntl
возвращает в случае успешного завершения значение, отличное от -1. Если у файла уже есть блокировки, препятствующие установке требуемой блокировки, структура
flock
обновляется соответствующими данными. Если блокировке ничто не мешает, структура
flock
не изменяется. Если вызов с командой
F_GETLK
не может получить информацию, он возвращает -1 для обозначения аварийного завершения.
Если вызов с командой
F_GETLK
завершился успешно (т. е. вернул значение, отличное от -1), вызвавшее его приложение должно проверить, изменено ли содержимое структуры
flock
. Поскольку значение
l_pid
содержит идентификатор блокирующего процесса (если таковой найден), это поле очень удобно для того, чтобы проверить, изменялась ли структура
flock
.
Значение F_SETLK параметра command
Эта команда пытается заблокировать или разблокировать участок файла, заданного
fildes
. В табл. 7.3 приведены значения полей структуры
flock
(отличающиеся от значений, применяемых командой
F_GETLK
).
Таблица 7.3
Значение
Описание
l_type
Одно из следующих: •
F_RDLCK
— для разделяемой или допускающей только чтение блокировки; •
F_WRLCK
— для исключительной или блокировки записи; •
F_UNLCK
— для разблокирования участка
l_pid
Не используется
Как и в случае
F_GETLK
, блокируемый участок определяется значениями элементов
l_start
,
l_whence
и
l_len
структуры
flock
. Если блокировка установлена, вызов
fcntl
вернет значение, отличное от -1, при аварийном завершении возвращается -1. Вызов завершается немедленно.
Значение F_SETLKW параметра command
Команда
F_SETLKW
аналогична команде
F_SETLK
за исключением того, что при невозможности установки блокировки вызов будет ждать до тех пор, пока такая возможность не представится. После перехода в состояние ожидания вызов завершится только, когда блокировка будет установлена или появится сигнал. Сигналы мы обсудим в главе 11.
Все блокировки файла, установленные программой, автоматически очищаются, когда закрывается соответствующий дескриптор файла. То же самое происходит, когда программа завершается.
Применение вызовов read и write при наличии блокировки
Когда вы применяете блокировку участков файла, очень важно использовать для доступа к данным низкоуровневые вызовы
read
и
write
вместо высокоуровневых функций
fread
и
fwrite
. Это необходимо, поскольку функции
fread
и
fwrite
выполняют внутри библиотеки буферизацию читаемых или записываемых данных, так что при выполнений вызова
fread
для считывания 100 байтов из файла может быть (и на самом деле почти наверняка будет), считано более 100 байтов, и дополнительные данные помещаются во внутрибиблиотечный буфер. Если программа применит функцию
fread
для считывания следующих 100 байтов, она на самом деле считает данные из буфера и не разрешит низкоуровневому вызову
read
извлечь больше данных из файла.
Для того чтобы понять, в чем тут проблема, рассмотрим две программы, которые хотят обновить один и тот же файл. Предположим, что файл содержит 200 байтов данных, все нули. Первая программа начинает работу и устанавливает блокировку на запись для первых 100 байтов файла. Затем она применяет функцию
fread
для считывания этих 100 байтов. Однако, как было показано в одной из предшествующих глав,
fread
будет каждый раз считывать больше, до
BUFSIZ
байтов, поэтому она на самом деле считает в память целиком весь файл, но программе вернет только первые 100 байтов.
Затем стартует вторая программа. Она устанавливает блокировку
write
на вторые 100 байтов файла. Это действие завершится успешно, поскольку первая программа заблокировала только первые 100 байтов. Вторая программа записывает двойки в байты с 100-го по 199-й, закрывает файл, снимает блокировку и завершается. В это время первая программа блокирует вторые 100 байтов файла и вызывает функцию
fread
для их считывания. Поскольку эти данные были уже занесены библиотекой в буфер, программа увидит 100 байтов нулей, а не 100 двоек, которые на самом деле хранятся в файле на жестком диске. Подобной проблемы не возникает, если вы применяете вызовы
read
и
write
.
Приведенное описание блокировки файла может показаться сложноватым, но ее труднее описать, чем применить. Поэтому выполните упражнение 7.9.
Упражнение 7.9. Блокировка файла с помощью вызова
fcntl
Давайте рассмотрим пример работы блокировки файла в программе lock3.с. Для опробования блокировки вам понадобятся две программы: одна для установки блокировки и другая для ее тестирования. Первая программа выполняет блокировку.