Основы программирования в Linux
l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 1534Testing F_RDLCK on region from 15 to 20F_RDLCK — Lock would succeed...Testing F_WRLCK on region from 25 to 30Lock would fail. F_GETLK returned:l_type 0, l_whence 0, l_start 10, l_len 20, l_pid 1534Testing F_RDLCK on region from 25 to 30F_RDLCK — Lock would succeed...Testing F_WRLCK on region from 40 to 45Lock would fail. F_GETLK returned:l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 1534Testing F_RDLCK on region from 40 to 45Lock would fail. F_GETLK returned:l_type 1, l_whence 0, l_start 40, l_len 10, l_pid 1534...Testing F_RDLCK on region from 95 to 100F_RDLCK - Lock would succeedКак это работает
Для каждой группы из пяти байтов в файле программа lock4 задает структуру участка файла для тестирования блокировок, которую она потом применяет для определения того, может ли этот участок быть заблокирован для чтения или записи. Возвращаемая информация показывает байты, относящиеся к участку файла, смещение от нулевого байта, которое могло бы вызвать аварийное завершение запроса на блокировку. Поскольку поле
возвращаемой структуры содержит идентификатор программы, владеющей в данный момент заблокированным файлом, программа задает ему значение -1 (некорректное значение) и затем проверяет, изменилось ли оно после завершения вызоваl_pid. Если участок в данный момент не заблокирован, полеfcntlне изменится.l_pidДля того чтобы понять вывод, следует заглянуть в заголовочный файл fcntl.h (обычно /usr/include/fcntl.h) и увидеть, что поле
, равное 1, вытекает из определенияl_typeкак 1, а равное 0 из определенияF_WRLCKкак 0. Таким образом, полеF_RDLCK, равное 1, говорит о том, что блокировка не будет установлена, поскольку существует блокировка на запись, а полеl_type, равное 0, свидетельствует о существовании блокировки на чтение. Для тех участков файла, которые не заблокировала программа lock3, могут быть установлены и разделяемая, и исключительная блокировки.l_typeДля байтов с 10-го по 30-й возможна установка разделяемой блокировки, поскольку блокировка, установленная программой lock3, не исключительная, а разделяемая. Для участка с 40-го по 50-й байт нельзя установить оба типа блокировки, поскольку lock3 задала исключительную (
) блокировку для этого участка.F_WRLCKПосле завершения программы lock4 необходимо немного подождать, чтобы программа lock3 завершила вызов
и закончила выполнение.sleepКонкурирующие блокировки
Теперь, когда вы увидели, как проверять существующие блокировки файла, давайте посмотрим, что произойдет, когда две программы состязаются за получение блокировки для одного и того же участка файла. Вы воспользуетесь снова программой lock3 для блокировки файла и новой программой lock5 для попытки установить новую блокировку файла. В завершение вы добавите в программу lock5 несколько вызовов для снятия блокировки (упражнение 7.11).
Упражнение 7.11. Конкурирующие блокировкиДалее приведена программа lock5.с, которая пытается заблокировать уже заблокированные участки файла вместо того, чтобы проверить состояние блокировки других частей файла.
После директив #include и объявлений откройте дескриптор файла.
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>const char *test_file = "/tmp/test_lock";int main() {int file_desc;struct flock region_to_lock;int res;file_desc = open(test_file, O_RDWR | O_CREAT, 0666);if (!file_desc) {fprintf(stderr, "Unable to open %s for read/write\n", test_file);exit(EXIT_FAILURE);}В оставшейся части программы задаются разные участки файла, и делается попытка установить для них блокировки разных типов:
region_to_lock.l_type = F_RDLCK;region_to_lock.l_whence = SEEK_SET;region_to_lock.l_start = 10;region_to_lock.l_len = 5;printf("Process %d, trying F_RDLCK, region %d to %d\n", getpid(), (int)region_to_lock.l_start,(int)(region_to_lock.l_start + region_to_lock.l_len));res = fcntl(file_desc, F_SETLK, &region_to_lock);if (res == -1) {printf("Process %d - failed to lock region\n", getpid());} else {printf("Process %d — obtained lock region\n", getpid());}region_to_lock.l_type = F_UNLCK;region_to_lock.l_whence = SEEK_SET;region_to_lock.l_start = 10;region_to_lock.l_len = 5;printf("Process %d, trying F_UNLCK, region %d to %d\n", getpid(), (int)region_to_lock.l_start,(int)(region_to_lock.l_start + region_to_lock.l_len));res = fcntl(file_desc, F_SETLK, &region_to_lock);if (res == -1) {printf("Process %d — failed to unlock region\n", getpid());} else {printf("Process %d — unlocked region\n", getpid());