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, 'конфликт блокировок
');
return 1;
}
lockinfо.l_type = F_RDLCK;
fcntl(fd, F_SETLK, &lockinfo);
Другой процесс мог заблокировать область между двумя вызовами fcntl()
, приводя к тому, что второму вызову fcntl()
не удается установить блокировку.
В качестве простого примера блокировки записей ниже приведена программа, которая открывает файл, устанавливает на нем блокировку чтения, освобождает блокировку чтения, устанавливает блокировку записи и закрывается. В промежутках между каждым из этих шагов программа ожидает, пока пользователь нажмет клавишу <Enter>. Если получить блокировку не удается, программа отображает идентификатор процесса, содержащего конфликтующую блокировку, и запрашивает у пользователя о необходимости повторить попытку. Запуск этой программы на двух терминалах облегчит экспериментирование с правилами блокировок POSIX.
1: /* lock.с */
2:
3: #include <errno.h>
4: #include <fcntl.h>
5: #include <stdio.h>
6: #include <unistd.h>
7:
8: /* выводит сообщение и ожидает нажатия
9: пользователем клавиши <Enter> */
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:
25: /* будет блокироваться весь файл */
26: lockinfo.l_whence = SEEK_SET;
27: lockinfo.l_start = 0;
28: lockinfo.l_len = 0;
29:
30: /* продолжать попытки, пока того желает пользователь */
31: while (1) {
32: lockinfo.l_type = type;
33: /* если блокировка получена, немедленно возвратиться */
34: if (!fcntl(fd, F_SETLK, &lockinfo)) return;
35:
36: /* найти, кто удерживает конфликтующую блокировку */
37: fcntl(fd, F_GETLK, &lockinfo);
38:
39: /* есть шанс, что блокировка освобождена между F_SETLK
40: и F_GETLK; проверить, существует ли еще конфликт
41: перед тем, как сообщать об этом */
42: if (lockinfo.l_type != F_UNLCK) {
43: sprintf (message, 'конфликт с процессом %d... нажмите '
44: '<enter> для повторения:', lockinfo.l_pid);
45: waitforuser(message);
46: }
47: }
48: }
49:
50: int main(void) {
51: int fd;
52:
53: /* подготовить файл для блокировки */
54: fd = open('testlockfile', O_RDWR | O_CREAT, 0666);
55: if (fd < 0) {
56: perror('open');
57: return 1;