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

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

locknone:

pid =

15491,

seq# -

locknone:

pid -

15491.

seq# =

locknone:

pid =

15491,

seq# =

locknone;

pid =

15491,

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491.

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491.

seq# =

locknone:

pid =

15491,

seq# =

locknone:

pid =

15491.

seq# =

ПРИМЕЧАНИЕ -

Обратите внимание, что функция main хранится в файле lockmain.c, но мы компилируем и компонуем эту программу с функциями, не осуществляющими никакой блокировки (листинг 9.1), поэтому мы называем ее locknone. Ниже будут использоваться другие версии функций ту 1оск и my unlock, и исполняемый файл будет называться по-другому в соответствии с используемым методом блокировки.

Установим значение последовательного номера в файле обратно в единицу и запустим программу в двух экземплярах в фоновом режиме. Результат будет такой:

Solaris % Solaris % locknone: locknone: locknone: locknone; locknone; locknone: locknone: locknone: locknone: locknone: locknone; locknone: locknone: locknone: locknone: locknone; locknone: locknone: locknone; locknone; locknone: locknone: locknone: locknone: locknone: locknone: locknone: locknone;

locknone & 1

locknone: pi

ocknone &

d = 15498, seq# = 1

= 15498, seq# =

- 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498. seq# =

= 15498. seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# -

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

= 15498, seq# =

- 15499, seq# =

= 15499, seq# =

= 15499, seq# =

= 15499, seq# =

= 15499, seq# =

- 15499, seq# =

= 15499, seq# =

= 15499, seq# =

= 15499, seq# =



locknone;

15499.

seql =

locknone:

15499,

seql =

locknone;

15499,

seql =

locknone:

15499,

seql =

locknone:

15499,

seql =

locknone:

15499,

seql =

locknone:

15499,

seql =

locknone:

15499,

seql =

locknone;

15499,

seql =

locknone;

15499,

seql =

locknone:

15499,

seql =

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

Первые двадцать строк вывода не содержат ошибок. Они были сформированы первым экземпляром программы (с идентификатором 15 498), Проблема возникает в первой строке, выведенной вторым экземпляром (идентификатор 15 499): он напечатал порядковый номер 1, Получилось это, скорее всего, так: второй процесс был запущен ядром, считал из файла порядковый номер (1), а затем управление было передано первому процессу, который работал до завершения. Затем второй процесс снова получил управление и продолжил выполняться с тем значением порядкового номера, которое было им уже считано (1). Это не то, что нам нужно. Каждый процесс считывает значение, увеличивает его и записывает обратно 20 раз (на экран выведено ровно 40 строк), поэтому конечное значение номера должно быть 40.

Нам нужно каким-то образом предотвратить изменение файла с порядковым номером на протяжении выполнения трех действий одним из процессов. Эти действия должны выполняться как атомарная операция по отношению к другим процессам. Код между вызовами ту 1 оск и niy unl ock представляет собой критическую область (глава 7).

При запуске двух экземпляров программы в фоновом режиме результат на самом деле непредсказуем. Нет никакой гарантии, что при каждом запуске мы будем получать один и тот же результат. Это нормально, если три действия будут выполняться как одна атомарная операция; в этом случае конечное значение порядкового номера все равно будет 40. Однако при неатомарном выполнении конечное значение часто будет отличным от 40, и это нас не устраивает. Например, нам безразлично, будет ли порядковый номер увеличен от 1 до 20 первым процессом и от 21 до 40 вторым или же процессы будут по очереди увеличивать его значение на единицу. Неопределенность не делает результат неправильным, а вот атомарность выполнения операций - делает. Однако неопределенность выполнения усложняет отладку программ.

9.2. Блокирование записей и файлов

Ядро Unix никак не интерпретирует содержимое файла, оставляя всю обработку записей приложениям, работающим с этим файлом. Тем не менее для описания предоставляемых возможностей используется термин блокировка записей . В действительности приложение указывает диапазон байтов файла для блокиро-



вания или разблокирования. Сколько логических записей помещается в этот диапазон - значения не имеет.

Стандарт Posix определяет один специальный диапазон с началом в О (начало файла) и длиной О байт, который устанавливает блокировку для всего файла целиком. Мы будем говорить о блокировке записей, подразумевая блокировку файла как частный случай.

Термин степень детализации (granularity) используется для описания минимального размера блокируемого объекта. Для стандарта Posix эта величина составляет 1 байт. Обычно степень детализации связана с максимальным количеством одновременных обращений к файлу. Пусть, например, с некоторым файлом одновременно работают пять процессов, из которых три считывают данные из файла и два записывают в него. Предположим также, что каждый процесс работает со своим набором записей и каждый запрос требует примерно одинакового времени для обработки (1 секунда). Если блокировка осуществляется на уровне файла (самый низкий уровень детализации), три считывающих процесса смогут работать со своими записями одновременно, а двум записывающим придется ждать окончания их работы. Затем запись будет произведена сначала одним из оставщихся процессов, а потом другим. Полное затраченное время будет порядка 3 секунд (это, разумеется, очень грубая оценка). Если же уровень детализации соответствует размеру записи (наилучший уровень детализации), все пять процессов смогут работать одновременно, поскольку они обрабатывают разные записи. При этом на выполнение будет затрачена только одна секунда.

ПРИМЕЧАНИЕ -

Потомки BSD поддерживают лишь блокировку файла целиком с помощью функции fioci<. Возможность заблокировать диапазон байтов не предусматривается.

История

За долгие годы было разработано множество методов блокировки файлов и записей. Древние программы вроде UUCP и демонов печати играли на реализации файловой системы (три из них описаны в разделе 9.8). Они работали достаточно медленно и не подходили для баз данных, которые стали появляться в начале 80-х.

Первый раз возможность блокировать файлы и записи появилась в Version 7, куда она была добавлена Джоном Бассом Gohn Bass) в 1980 году в виде нового системного вызова locking. Это блокирование было обязательным (mandatory locking); его унаследовали многие версии System III и Xenix. (Разница между обязательным и рекомендательным блокированием и между блокированием записей и файлов описана далее в этой главе.)

Версия 4.2BSD предоставила возможность блокирования файлов (а не записей) функцией flock в 1983. В 1984 году стандарт /usr/group (один из предшественников Х/Ореп) определил функцию lockf, которая осуществляла только исключающую блокировку (на запись), но не совместную.

В 1984 году в System V Release 2 была добавлена возможность рекомендательной блокировки записей с помощью fcntl. Функция lockf в этой версии также



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