Следующие два элемента, 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()
не удается установить блокировку.
В качестве простого примера блокировки записей ниже приведена программа, которая открывает файл, устанавливает на нем блокировку чтения, освобождает блокировку чтения, устанавливает блокировку записи и закрывается. В промежутках между каждым из этих шагов программа ожидает, пока пользователь нажмет клавишу
1: /* lock.с */
2:
3: #include
4: #include
5: #include
6: #include
7:
8: /* выводит сообщение и ожидает нажатия
9: пользователем клавиши
10: void waitforuser(char * message) {
11: char buf[10];
12:
13: printf("%s", message);
14: fflush(stdout);
15:
16: fgets(buf, 9, stdin);
17: }
18:
19: /* Получает блокировку заданного типа на файловом дескрипторе fd.
20: Типом блокировки может быть F_UNLCK, F_RDLCK или F_WRLCK */
21: void getlock(int fd, int type) {
22: struct flock lockinfo;
23: char message[80];
24: