Книга: Linux программирование в примерах
14.2.2.2. Установка и снятие блокировок
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 и устанавливает в errnoEACCESS
.
Возвращаемое значение равно 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
:
lock.l_whence = ... ; /* Как раньше */
lock.l_start = ... ; /* Как раньше */
lock.l_len = ... ; /* Как раньше */
lock.l_type = F_UNLCK; /* Разблокировать */
if (fcntl(fd, F_SETLK, &lock) < 0) {
/* обработать ошибку */
}
/* Блокировка была снята */
Код, использующий lockf()
, несколько проще. Для краткости мы опустили проверку ошибок:
off_t curpos, len;
curpos = lseek(fd, (off_t)0, SEEK_CUR); /* Получить текущее положение */
len = ... ; / * Установить соответствующее число блокируемых байтов */
lockf(fd, F_LOCK, len); / * Осуществить блокировку */
/* ...здесь использование заблокированного участка... */
lseek(fd, curpos, SEEK_SET); / * Вернуться к началу блокировки */
lockf(fd, F_ULOCK, len); /* Разблокировать файл */
Если вы не освободите блокировку явным образом, операционная система сделает это за вас в двух случаях. Первый случай, когда процесс завершается (либо при возвращении из main()
, либо с использованием функции exit()
, которую мы рассматривали в разделе 9.1.5.1 «Определение статуса завершения процесса»). Другим случаем является вызов close()
с дескриптором файла: больше об этом в следующем разделе.
- 14.2.2.3. Предостережения по поводу блокировок
- Расширенная установка InterBase-сервера
- Снятие ответственности с клиента
- Установка системы на уже подготовленный жесткий диск
- Установка файлов занятий
- 2 Установка системы
- Глава 4. Установка и конфигурирование сетевых интерфесов
- Часть III Установка, настройка и оптимизация операционной системы
- Демонтаж и установка МП
- Установка
- Установка пароля
- Установка ЦП