Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 [ 68 ] 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

имелась, но она осуществляла просто вызов fcntl. (Многие нынешние версии также реализуют lockf через вызов fcntl.) В 1986 году в версии System V Release 3 появилась обязательная блокировка записей с помощью fcntl. При этом использовался бит set-group-ID (установка идентификатора группы) - об этом методе рассказано в разделе 9.5.

В 1988 году стандарт Posix. 1 включил в себя рекомендательную и обязательную блокировку файлов и записей с помощью функции fcntl, и это именно то, что является предметом обсуждения данной главы. Стандарт Х/Ореп Portability Guide Issue 3 (XPG3, 1988) также указывает на необходимость осуществления блокировки записей через fcntl.

9.3. Блокирование записей с помощью fcntl по стандарту Posix

Согласно стандарту Posix, интерфейсом для блокировки записей является функция fcntl:

linclude <fcntl .h>

int fcntl (int fd. int cmd. ... /* struct flock *arg */ ): /* Возвращает -1 в случае ошибки; результат, возвращаемый в случае успешного завершения, зависит от аргумента and */

Для блокировки записей используются три различных значения аргумента cmd. Эти три значения требуют, чтобы третий аргумент, arg, являлся указателем на структуру f 1 оск:

struct flock {

short l type: /* F RDLCK, F WRLCK. F UNLCK */

short l whence: /* SEEKJET. SEEK CUR, SEEKJND */

off t l start: /* относительный сдвиг в байтах */

off t IJen; /* количество байтов: О означает до конца файла */

pid t l pid: /* PID, возвращаемый F GETLK */

Вот три возможные команды (значения аргумента cmd):

ш F SETLK - получение блокировки (l type имеет значение либо F RDLCK, либо F WRLCK) или сброс блокировки (1 type имеет значение F UNLCK), свойства которой определяются структурой flock, на которую указывает arg.

Если процесс не может получить блокировку, происходит немедленный возврат с ошибкой EACCESS или EAGAIN,

F SETLKW - эта команда идентична предыдущей. Однако при невозможности блокирования ресурса процесс приостанавливается, до тех пор пока блокировка не сможет быть получена (W в конце команды означает wait ).

ж F GETLK - проверка состояния блокировки, на которую указывает arg. Если в данный момент блокировка не установлена, поле l type структуры fl оск, на которую указывает arg, будет иметь значение F UNLCK. В противном случае в структуре f 1 оск, на которую указывает arg, возвращается информация об установленной блокировке, включая идентификатор процесса, заблокировавшего ресурс.



Обратите внимание, что последовательный вызов FGETLK и FSETLK не является атомарной операцией. Если мы вызвали FGETLK и она вернула значение F UNLCKb поле l type, это не означает, что немедленный вызов F SETLK будет успешным. Между этими двумя вызовами другой процесс мог уже заблокировать ресурс.

Причина, по которой была введена команда FGETLK, - необходимость получения информации о блокировке в том случае, когда FSETLK возвращает ошибку. Мы можем узнать, кто и каким образом заблокировал ресурс (на чтение или на запись). Но и в этом случае мы должны быть готовы к тому, что F GETLK вернет результат F UNLCK, поскольку между двумя вызовами другой процесс мог освободить ресурс.

Структура flock описывает тип блокировки (чтение или запись) и блокируемый диапазон. Как и в 1 seek, начальный сдвиг представляет собой сдвиг относительно начала файла, текущего положения или конца файла, и интерпретируется в зависимости от значения поля l whence (SEEK SET, SEEK CUR, SEEK END).

Поле 1 1 en указывает длину блокируемого диапазона. Значение О соответствует блокированию от 1 sta rt до конца файла. Существуют, таким образом, два способа заблокировать файл целиком:

1. Указать l whence = SEEK SET, l start = QH 1 1еп = 0.

2. Перейти к началу файла с помощью Iseek, затем указать l whence = SEEK CUR, l start = QHl len = Q.

Чаще всего используется первый метод, поскольку он предусматривает единственный вызов (fcntl - см. также упражнение 9.10).

Блокировка может быть установлена либо на чтение, либо на запись, и для конкретного байта файла может быть задан только один тип блокировки. Более того, на конкретный байт может быть установлено несколько блокировок на чтение, но только одна блокировка на запись. Это соответствует тому, что говорилось о блокировках чтения-записи в предыдущей главе. Естественно, при попытке установить блокировку на чтение для файла, открытого только на запись, будет возвращена ошибка.

Все блокировки, установленные конкретным процессом, снимаются при закрытии дескриптора файла этим процессом и при завершении его работы. Блокировки не наследуются дочерним процессом при вызове fork.

ПРИМЕЧАНИЕ-

Снятие блокировок при завершении процесса обеспечивается только для блокировок записей fcntl и (в качестве дополнительной возможности) для семафоров System V. Для других средств синхронизации (взаимных исключений, условных переменных, блокировок чтения-записи и семафоров Posix) автоматическое снятие при завершении процесса не предусматривается. Об этом мы говорили в конце раздела 7.7,

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



linclude unpipc.h

void

lock(int fd)

{

struct flock lock:

lock.l type = F WRLCK:

lock,l whence = SEEK SET:

lock.l start = 0:

lock.ljen = 0:

Fcntl(fd. F SETLKW. &lock)

void

my unlock(int fd)

struct flock lock:

lock.l type = F UNLCK:

lock.l whence = SEEK SET;

lock.l start = 0:

lock.ljen = 0;

Fcntl(fd. F SETLK. &lock):

/* блокирование всего файла на запись */

/* разблокирование всего файла */

Обратите внимание, что мы устанавливаем блокировку на запись, что гарантирует единственность изменяющего данные процесса (см. упражнение 9.4). При получении блокировки мы используем команду F SETLKW, чтобы приостановить выполнение процесса при невозможности установки блокировки.

ПРИМЕЧАНИЕ -

Зная определение структуры flock, приведенное выше, мы могли бы проинициализи-ровать структуру ту 1оск как

static struct flock lock = { F WRLCK. SEEKJET. 0. 0, 0 }:

HO это неверно. Posix определяет только обязательные поля структуры, а реализации могут менять их порядок и добавлять к ним дополнительные.

Мы не приводим результат работы программы, но она, судя по всему, работает правильно. Выполнение этой программы не дает возможности утверждать, что в ней нет ошибок. Если результат оказывается неправильным, то можно сказать с уверенностью, что что-то не так. Но успешное выполнение программы еще ни о чем не говорит. Ядро могло выполнить сначала одну программу, затем другую.

Пример

Вернемся к нашему примеру из листинга 9.2 и перепишем функции ту 1оск и ту unl оск из листинга 9.1 так, чтобы воспользоваться блокировкой записей Posix, Текст этих функций приведен в листинге 9.3,

Листинг 9.3. Блокировка записей fcntl по стандарту Posix

lock/lockfcntl,с



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 [ 68 ] 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.