Значение
F_UNLCK
для
l_type
снимает блокировку. В общем, это простейший способ снять те самые блоки, которые были установлены ранее, но можно «расщепить» блок, освободив диапазон байтов в середине ранее установленного более крупного блока. Например:
struct employee { /* что угодно */ }; /* Описание сотрудника */
struct flock lock; /* Структура блока */
...
/* Заблокировать сотрудников 6-8 */
lock.l_whence = SEEK_SET; /* Абсолютное положение */
lock.l_start = 5 * sizeof(struct employee); /* Начало 6-й структуры */
lock.l_len = sizeof(struct employee) * 3; /* Заблокировать 3 записи */
/* ...установка блокировки (см. следующий раздел)... */
/* Освобождение записи 7: предыдущий блок расщепляется на два: */
lock.l_whence = SEEK_SET; /* Абсолютное положение */
lock.l_start = 6 * sizeof(struct employee); /* Начало 7-й структуры */
lock.l_len = sizeof(struct employee) * 1; /* Разблокирование 1-й записи */
/* ...снятие блокировки (см. следующий раздел)... */
14.2.2.2. Установка и снятие блокировок
После заполнения структуры
struct flock
следующим шагом является запрос блокировки. Этот шаг осуществляется с помощью соответствующего значения аргумента
cmd
функции
fcntl()
:
F_GETLK
Узнать, можно ли установить блокировку.
F_SETLK
Установить или снять блокировку.
F_SETLKW
Установить блокировку, подождав, пока это будет возможным.
Команда
F_GETLK
является командой «Мама, можно мне?» Она осведомляется, доступна ли описанная
struct flock
блокировка. Если она доступна, блокировка
не устанавливается; вместо этого операционная система изменяет поле
l_type
на
F_UNLCK
. Другие поля остаются без изменений.
Если блокировка недоступна, операционная система заполняет различные поля сведениями, описывающими уже установленные блокировки, которые препятствуют установке новой. В этом случае
l_pid
содержит PID процесса, владеющего соответствующей блокировкой.
[152] Если блокировка уже установлена, нет другого выбора, кроме ожидания в течение некоторого времени и новой попытки установки блокировки или вывода сообщения об ошибке и отказа от дальнейших попыток.
Команда
F_SETLK
пытается установить указанную блокировку. Если
fcntl()
возвращает 0, блокировка была успешно установлена. Если она возвращает -1, блокировку установил другой процесс. В этом случае в errno устанавливается либо
EAGAIN
(попытайтесь снова позже) или
EACCESS
(нет доступа). Возможны два значения, чтобы удовлетворить старым системам.
Команда
F_SETLKW
также пытается установить указанную блокировку. Она отличается от
F_SETLK
тем, что будет ждать, пока установка блокировки не окажется возможной.
Выбрав соответствующее значение для аргумента
cmd
, передайте его в качестве второго аргумента
fcntl()
вместе с указателем на заполненную структуру
struct flock
в качестве третьего аргумента:
struct flock lock;
int fd;
/* ...открыть файл, заполнить struct flock... */
if (fcntl(fd, F_SETLK, &lock) < 0) {
/* Установить не удалось, попытаться восстановиться */
}
Функция
lockf()
[153] предоставляет альтернативный способ установки блокировки
в текущем положении файла.
#include <sys/file.h> /* XSI */
int lockf(int fd, int cmd, off_t len);
Дескриптор файла
fd
должен быть открыт для записи.
len
указывает число блокируемых байтов: от текущего положения (назовем его
pos
) до
pos + len
байтов, если
len
положительно, или от
pos - len
до
pos - 1
, если len отрицательно. Команды следующие:
F_LOCK
Устанавливает исключительную блокировку диапазона. Вызов блокируется до тех пор, пока блокировка диапазона не станет возможной.
F_TLOCK
Пытается установить блокировку. Это похоже на
F_LOCK
, но если блокировка недоступна,
F_TLOCK
возвращает ошибку.
F_ULOCK
Разблокирует указанный раздел. Это может вызвать расщепление блокировки, как описано выше.
F_TEST
Проверяет, доступна ли блокировка. Если доступна, возвращает 0 и устанавливает блокировку. В противном случае возвращает -1 и устанавливает в
errno
EACCESS
.
Возвращаемое значение равно 0 в случае успеха и -1 при ошибке, с соответствующим значением в
errno
. Возможные значения ошибок включают:
EAGAIN
Файл заблокирован, для
F_TLOCK
или
F_TEST
.
EDEADLK
Для
F_TLOCK
эта операция создала бы тупик.
[154]ENOLCK
Операционная система не смогла выделить блок.
Полезна комбинация
F_TLOCK
и
EDEADLK
: если вы знаете, что тупик не может возникнуть никогда, используйте
F_LOCK
. В противном случае, стоит обезопасить себя и использовать
F_TLOCK
. Если блокировка доступна, она осуществляется, но если нет, у вас появляется возможность восстановления вместо блокирования в ожидании, возможно, навечно.
Завершив работу с заблокированным участком, его следует освободить. Для
fcntl()
возьмите первоначальную
struct lock
, использованную для блокирования, и измените поле
l_type
на
F_UNLCK
. Затем используйте
F_SETLK
в качестве аргумента
cmd
: