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

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

и если они не выполнялись параллельно, мы не имеем возможности увидеть ошибку. Увеличить шансы обнаружения ошибки можно, изменив функцию та i п таким образом, чтобы последовательный номер увеличивался 10 ООО раз, и запустив 20 экземпляров программы одновременно. Если начальное значение последовательного номера в файле было 1, мы можем ожидать, что после завершения работы всех этих процессов мы увидим в файле число 200 001.

Пример: упрощение с помощью макросов

в листинге 9.3 установка и снятие блокировки занимали шесть строк кода. Мы должны вьщелить место под структуру, инициализировать ее и затем вызвать fcntl. Программы можно упростить, если определить следующие семь макросов, которые взяты из раздела 12.3 [21]:

fdefine read lock(fd, offset, whence, len) \

lock reg(fd. F SETLK, FJDLCK, offset, whence, len) fdefine readw lock(fd, offset, whence, len) \

lock reg(fd. F SETLKW. F ROLCK. offset, whence, len) fdefine write lock(fd. offset, whence, len) \

lock reg(fd, F SETLK, F WRLCK. offset, whence, len) fdefine writew lock(fd. offset, whence, len) \

lock reg(fd, F SETLKW, F WRLCK, offset, whence, len) fdefine unJock(fd. offset, whence, len) \

lock reg(fd, F SETLK, F UNLCK, offset, whence, len) fdefine is readJockable(fd, offset, whence, len) \

lock test(fd, F RDLCK, offset, whence, len) fdefine is write lockable(fd, offset, whence, len) \

lock test(fd, F WRLCK, offset, whence, len)

Эти макросы используют наши функции lock reg и lock test, текст которых приведен в листингах 9.4 и 9.5. С ними нам уже не нужно заботиться об инициализации структур и вызове функций. Первые три аргумента специально сделаны совпадающими с первыми тремя аргументами функции 1 seek.

Мы также определяем две функции-обертки, Lock reg и Lock test, завершающие свое выполнение с возвратом ошибки fcntl, и семь макросов с именами, начинающимися с заглавной буквы, чтобы эти функции вызывать.

С помощью новых макросов мы можем записать функции ту 1 оск и my unl оск

из листинга 9.3 как

fdefine rnyjock(fd) (WritewJock(fd, О, SEEKJET, 0)) fdefine my unlock(fd) (UnJock(fd, 0, SEEKJET, 0))

Листинг 9.4. Вызов fcntl для получения и снятия блокировки

lib/lock reg.c

1 finclude unpipc.h

2 int

3 lock reg(int fd, int cmd, int type, off t offset, int whence, off t len)

5 struct flock lock:

6 1 ock. 1 Jype - type: /* F RDLCK. F WRLCK, FJNLCK */

7 lock,l start - offset: /* сдвиг no отношению к l whence */

8 lock.l whence - whence: /* SEEK SET, SEEK CUR, SEEK END */



9 lock.ljen - len; /* количество байтов (О - до конца файла) */

10 returnC fcntl (fd, cmd. &1оск) ): /* -1 в случае ошибки */

И }

Листинг 9.5. Вызов fcntl для проверки состояния блокировки

lib/lock test.c

1 linclude unpipc.h

2 pid t

3 lock test(int fd. int type, off t offset, int whence, off t len)

5 struct flock lock:

6 lock.l type = type: /* F RDLCK or F WRLCK */

7 lock.l start = offset: /* сдвиг no отношению к l whence */

8 lock.l whence = whence: /* SEEKJET, SEEK CUR, SEEKJND */

9 lock.ljen - len: /* количество байтов, О - до конца файла */

10 if (fcntKfd, F GETLK, &1оск) == -1)

И return(-l); /* непредвиденная ошибка */

12 if (lock,l type - F UNLCK)

13 return(O): /* false, область не заблокирована другим

процессом */

14 return(lock.l pid): /* true, возвращается положительный PID процесса,

заблокировавшего ресурс */

15 }

9.4. Рекомендательная блокировка

Блокировка записей по стандарту Posix называется рекомендательной. Ядро хранит информацию обо всех заблокированных различными процессами файлах, но оно не предотвращает запись в заблокированный на чтение процесс. Ядро также не предотвращает чтение из файла, заблокированного на запись. Процесс может игнорировать рекомендательную блокировку (advisory lock) и действовать по своему усмотрению (если у него имеются соответствующие разрешения на чтение и запись).

Рекомендательные блокировки отлично подходят для сотрудничающих процессов (cooperating processes). Примером сотрудничающих процессов являются сетевые демоны: все они находятся под контролем системного администратора. Пока в файл, содержащий порядковый номер, запрещена запись, никакой процесс не сможет его изменить.

Пример: несотрудничающие процессы

Мы можем проиллюстрировать рекомендательный характер блокировок, запустив два экземпляра нашей программы, один из которых (lockfcntl) использует функции из листинга 9.3 и блокирует файл перед увеличением последовательного номера, а другой (1 оскпопе) использует функции из листинга 9.1 и не устанавливает никаких блокировок:



Solaris %

lockfcntl & locknone &

lockfcntl

pid -

18816. seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid -

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid =

18816, seq#

lockfcntl

pid -

18816. seq#

- 10

lockfcntl

pid =

18816, seq#

= 11

locknone;

pid =

18817, seq# =

locknone;

pid =

18817, seq# =

locknone:

pid =

18817, seq# =

locknone:

pid -

18817, seq# =

locknone:

pid =

18817. seq# =

locknone;

pid =

18817, seq# -

locknone:

pid -

18817, seq# =

locknone:

pid =

18817, seq# =

lockfcntl

pid =

18816, seq#

= 12

lockfcntl

pid -

18816, seq#

= 13

lockfcntl

pid =

18816, seq#

= 14

lockfcntl

pid =

18816. seq#

- 15

lockfcntl

pid =

18816, seq#

= 16

lockfcntl

pid =

18816, seq#

= 17

lockfcntl

pid -

18816, seq#

- 18

lockfcntl

pid =

18816, seq#

= 19

lockfcntl

pid =

18816, seq#

= 20

locknone:

pid -

18817, seq# =

locknone:

pid =

18817, seq# -

locknone:

pid -

18817, seq#-

locknone:

pid -

18817, seq# =

locknone:

pid -

18817, seq# =

locknone:

pid =

18817, seq# -

locknone;

pid =

18817, seq# =

locknone:

pid =

18817, seq# =

locknone:

pid =

18817, seq# =

locknone:

pid =

18817, seq# =

locknone:

pid -

18817, seq# =

locknone:

pid =

18817, seq# =

Программа 1 ockfcntl запускается первой, но в тот момент, когда она выполняет три действия для увеличения порядкового номера с И до 12 (в этот момент файл заблокирован), ядро переключается на второй процесс и запускает программу locknone. Этот процесс считывает значение И из файла с порядковым номером и использует его. Рекомендательная блокировка, установленная для этого файла программой 1 ockfcntl, никак не влияет на работу программы 1 ocknone.

9.5. Обязательная блокировка

Некоторые системы предоставляют возможность установки блокировки другого типа - обязательной (mandatory locking). В этом случае ядро проверяет все вызовы read и write, блокируя их при необходимости. Если для дескриптора уста-



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.
Копирование материалов разрешено исключительно при условии цититирования.