Чтение онлайн

на главную - закладки

Жанры

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

13.3.2. Блокировка записей

С целью преодоления проблем, присущих блокировочным файлам, в System V и BSD 4.3 была добавлена блокировка записей, реализуемая с помощью системных вызовов

lockf
и
flock
соответственно. Стандарт POSIX определил третий механизм для блокировки записей, который использует системный вызов
fcntl
. Хотя Linux поддерживает все три интерфейса, мы обсудим только интерфейс POSIX, поскольку сейчас его поддерживают почти все платформы Unix. Кроме того, функция
lockf
реализована как интерфейс для
fcntl
, поэтому оставшаяся часть данного обсуждения касается обоих методов.

Существуют два значительных отличия между блокировками записей и блокировочными файлами. Во-первых, блокировки записей

применяются к произвольной части файла. Например, процесс А может заблокировать байты с 50-го по 200-й файла, в то время как другой процесс блокирует байты с 2500-го по 3000-й без конфликта двух блокировок. Мелкомодульное блокирование полезно, когда нескольким процессам необходимо обновить один файл. Еще одно преимущество блокирования записей заключается в том, что блокировки удерживаются в ядре, а не в файловой системе. По окончании процесса все блокировки, которые он содержит, освобождаются.

Как и блокировочные файлы, блокировки POSIX также являются рекомендательными. Linux, как и System V, предоставляет обязательный вариант блокирования записей, который можно использовать, но нарушая при этом переносимость. Блокирование файлов может работать или не работать в сетевой файловой системе (NFS). В последних версиях Linux блокирование файлов работает в NFS, если на всех машинах, участвующих в блокировке, выполняется демон блокировки NFS

lockd
.

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

Множество блокировок одного процесса никогда не конфликтуют друг с другом [90] .

Если процесс имеет блокировку чтения на байтах 200—250 и пытается установить блокировку записи на байты 200–225, ему это удастся. Исходная блокировка смещается и становится блокировкой чтения на байтах 226–250, а новая блокировка записи устанавливается на байты 200–225 [91] . Это позволяет предотвратить взаимоблокировку одного процесса (хотя ситуация взаимоблокировки нескольких процессов по-прежнему возможна).

90

Эта ситуация более сложна для потоков. Многие ядра и библиотеки Linux рассматривают потоки как разные процессы, что увеличивает потенциал возникновения конфликтов файловых блокировок между потоками (а это не совместимо со стандартной моделью потоков POSIX). Linux предлагает более традиционную модель потоков, при которой файловые блокировки разделяются между всеми потоками одного процесса, но в многопоточных программах лучше применять потоковые механизмы блокировки POSIX, а не полагаться на поведение файловых блокировок.

91

Эта манипуляция блокировками происходит атомарно — не имеет значения, какая часть области разблокирована.

Блокирование записей POSIX осуществляется с помощью системного вызова

fcntl
. В главе 11 было показано, что
fcntl
выглядит следующим образом.

#include <fcntl.h>

int fcntl (int fd, int command, long arg);

Для всех операций блокировки третий параметр (

arg
) указывает на структуру
struct flock
, представленную ниже.

#include <fcntl.h>

struct flock {

 short l_type;

 short l_whence;

 off_t l_start;

 off_t l_len;

 pid_t l_pid;

};

Первый элемент,

l_type
, определяет
тип установленной блокировки.

F_RDLCK
Устанавливается блокировка чтения (разделяемая).
F_WRLCK
Устанавливается блокировка записи (эксклюзивная).
F_UNLCK
Снимается существующая блокировка.

Следующие два элемента,

l_whence
и
l_start
, определяют начало области тем же способом, что и файловые смещения, передаваемые в
lseek
.
l_whence
сообщает о способе интерпретации
l_start
и принимает одно из значений
SEEK_SET
,
SEEK_CUR
или
SEEK_END
; более подробно эти значения рассматривались в главе 11. Следующий элемент,
l_len
, сообщает размер блокировки в байтах. Если
l_len
равно 0, считается, что блокировка распространяется до конца файла. Последний элемент,
l_pid
, используется только тогда, когда запрашиваются блокировки. Он устанавливается в идентификатор процесса, владеющего запрашиваемой блокировкой.

Существуют три команды

fcntl
, относящиеся к блокировке файла. Они передаются
fcntl
во втором аргументе,
fcntl
возвращает
– 1
в случае ошибки и
0
 — в противном случае. Ниже перечислены допустимые значения параметра
command
.

F_SETLK
Устанавливает блокировку, описанную в
arg
. Если блокировку невозможно выдать из-за конфликта с блокировками других процессов, возвращается
EAGAIN
. Если
l_type
устанавливается в
F_UNLCK
, существующая блокировка снимается.
F_SETLKW
Подобно
F_SETLK
, но блокирует только при условии предоставления блокировки. Если сигнал поступает во время блокирования процесса, вызов
fcntl
возвращает
EAGAIN
.
F_GETLK
Проверяет возможность выдачи описанной в
arg
блокировки. Если блокировка предоставляется, содержимое
struct flock
не меняется, кроме
l_type
, который устанавливается в
F_UNLCK
. Если блокировка не выдается,
l_pid
устанавливается в идентификатор процесса, содержащего конфликтующую блокировку. Значение 0 возвращается независимо от того, будет ли предоставлена блокировка.

Хотя

F_GETLK
позволяет процессу проверить, будет ли выдана блокировка, следующий код все еще не сможет получить блокировку.

fcntl(fd, F_GETLK, &lockinfo);

if (lockinfо.l_type != F_UNLCK) {

 fprintf(stderr, "конфликт блокировок\n");

 return 1;

}

lockinfо.l_type = F_RDLCK;

fcntl(fd, F_SETLK, &lockinfo);

Другой процесс мог заблокировать область между двумя вызовами

fcntl
, приводя к тому, что второму вызову
fcntl
не удается установить блокировку.

В качестве простого примера блокировки записей ниже приведена программа, которая открывает файл, устанавливает на нем блокировку чтения, освобождает блокировку чтения, устанавливает блокировку записи и закрывается. В промежутках между каждым из этих шагов программа ожидает, пока пользователь нажмет клавишу <Enter>. Если получить блокировку не удается, программа отображает идентификатор процесса, содержащего конфликтующую блокировку, и запрашивает у пользователя о необходимости повторить попытку. Запуск этой программы на двух терминалах облегчит экспериментирование с правилами блокировок POSIX.

Поделиться:
Популярные книги

Жалкая

Макинтайер Эмили
3. Долго и Несчастливо
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Жалкая

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец

Академия проклятий. Книги 1 - 7

Звездная Елена
Академия Проклятий
Фантастика:
фэнтези
8.98
рейтинг книги
Академия проклятий. Книги 1 - 7

Измена. Верни мне мою жизнь

Томченко Анна
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Верни мне мою жизнь

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Сердце для стража

Каменистый Артем
5. Девятый
Фантастика:
фэнтези
боевая фантастика
9.20
рейтинг книги
Сердце для стража

Черный Маг Императора 11

Герда Александр
11. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Черный Маг Императора 11

Имя нам Легион. Том 3

Дорничев Дмитрий
3. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 3

Жена фаворита королевы. Посмешище двора

Семина Дия
Фантастика:
фэнтези
5.00
рейтинг книги
Жена фаворита королевы. Посмешище двора

Как я строил магическую империю 5

Зубов Константин
5. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 5

Блуждающие огни 2

Панченко Андрей Алексеевич
2. Блуждающие огни
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Блуждающие огни 2

Ратник

Ланцов Михаил Алексеевич
3. Помещик
Фантастика:
альтернативная история
7.11
рейтинг книги
Ратник

Маленькая слабость Дракона Андреевича

Рам Янка
1. Танцы на углях
Любовные романы:
современные любовные романы
эро литература
5.25
рейтинг книги
Маленькая слабость Дракона Андреевича