Как и блокировочные файлы, блокировки POSIX также являются рекомендательными. Linux, как и System V, предоставляет обязательный вариант блокирования записей, который можно использовать, но нарушая при этом переносимость. Блокирование файлов может работать или не работать в сетевой файловой системе (NFS). В последних версиях Linux блокирование файлов работает в NFS, если на всех машинах, участвующих в блокировке, выполняется демон блокировки NFS lockd
.
При блокировке записей используются два типа блокировок: блокировка чтенияи блокировка записи. Блокировки чтения также известны как разделяемые блокировки, поскольку несколько процессов могут одновременно удерживать блокировки чтения на одной и той же области. Для нескольких процессов чтение структуры данных, которая не обновляется, безопасно всегда. Когда процессу необходимо записать файл, ему понадобится блокировка записи (или эксклюзивная блокировка). Только один процесс может удерживать блокировку на определенной записи, и пока блокировка записи существует, блокировки чтения не допускаются. Это гарантирует, что процесс не повлияет на модули чтения, пока будет осуществлять запись в область.
Множество блокировок одного процесса никогда не конфликтуют друг с другом [90] Эта ситуация более сложна для потоков. Многие ядра и библиотеки Linux рассматривают потоки как разные процессы, что увеличивает потенциал возникновения конфликтов файловых блокировок между потоками (а это не совместимо со стандартной моделью потоков POSIX). Linux предлагает более традиционную модель потоков, при которой файловые блокировки разделяются между всеми потоками одного процесса, но в многопоточных программах лучше применять потоковые механизмы блокировки POSIX, а не полагаться на поведение файловых блокировок.
.
Если процесс имеет блокировку чтения на байтах 200—250 и пытается установить блокировку записи на байты 200–225, ему это удастся. Исходная блокировка смещается и становится блокировкой чтения на байтах 226–250, а новая блокировка записи устанавливается на байты 200–225 [91] Эта манипуляция блокировками происходит атомарно — не имеет значения, какая часть области разблокирована.
. Это позволяет предотвратить взаимоблокировку одного процесса (хотя ситуация взаимоблокировки нескольких процессов по-прежнему возможна).
Блокирование записей POSIX осуществляется с помощью системного вызова fcntl()
. В главе 11 было показано, что fcntl()
выглядит следующим образом.
#include
int fcntl (int fd, int command, long arg);
Для всех операций блокировки третий параметр ( arg
) указывает на структуру struct flock
, представленную ниже.
#include
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
позволяет процессу проверить, будет ли выдана блокировка, следующий код все еще не сможет получить блокировку.
Читать дальше