Анимация
JavaScript
|
Главная Библионтека Хотя в документации PHP и сказано, что flock() работает во всех операционных системах (в том числе и под Windows), мои тесты показали, что как раз для Windows это не так. А именно, в этой системе функция всегда возвращает индикатор провала, независимо от того, правильно она вызывается, или нет. Возможно, в будущих версиях PHP это досадное недоразумение будет исправлено. осуществляется не на уровне ядра системы, а на уровне программы. Поясню на примере. Однажды я прочитал одно замечательное сравнение рекомендательной блокировки с перекрестком, на котором установилось довольно оживленное движение, регулируемое светофором. Когда горит красный, одни машины стоят, а другие проезжают. В принципе, любая машина может, так сказать, проехать наперекор правилам дорожного движения, не дожидаясь зеленого сигнала, но в таком случае возможны аварии. Рекомендательная блокировка работает точно таким же образом. А именно, процессы, которые ей пользуются, будут работать с разделяемым файлом правильно, а ос-тальные как-нибудь да будут, пока не произойдет "столкновение". С другой стороны, "жесткая блокировка" (которая в PHP не поддерживается) подобна шлагбауму: никто не сможет проехать, пока его не поднимут. О жесткой блокировке мы в этой книге говорить не будем. Единственная функция, которая занимается управлением блокировками в PHP, называется flock() . bool flock(int $f, int $operation [, int& $wouldblock]) Функция устанавливает для указанного открытого дескриптора файла $f режим блокировки, который бы хотел получить текущий процесс. Этот режим задается аргументом $operation и может быть одной из следующих констант: □ LOCK SH (или 1) - разделяемая блокировка; □ LOCK EX (или 2) - исключительная блокировка; □ LOCK UN (или 3) - снять блокировку; □ LOCKNB (или 4) - эту константу нужно прибавить к одной из пред1дущих, если вы не хотите, чтобы программа "подвисала" на flock() в ожидании своей очереди, а сразу возвращала управление. В случае, если был затребован режим без ожидания, и блокировка не была успешно установлена, в необязательный параметр-переменную $wouldblock будет записано значение истина true. В случае ошибки функция, как всегда, возвращает false, а в случае успешного завершения - true. Типы блокировок Вспоминаю, когда я впервые столкнулся с описанием возможностей рекомендательных блокировок Си в одном из электронных справочников (кажется, это был man операционной системы FreeBSD), я был неприятно удивлен, - настолько все выглядело сложным и нелогичным. Слава Богу, на самом деле ситуация далеко не так плачевна. Сейчас я постараюсь понятным языком разъяснить все, что касается блокировок в языке PHP. Что же из себя представляют понятия исключительная блокировка и разделяемая блокировка? Исключительная блокировка Вернемся к нашему примеру с процессами-писателями. Каждый такой процесс страстно желает, чтобы в некоторый момент (точнее, когда он уже почти готов начать писать) он был единственным, кому разрешена запись в файл. Он хочет стать исключительным. Отсюда и название блокировки, которую процесс должен для себя установить. Вызвав функцию flock($f,LOCK EX), он может быть абсолютно уверен, что все остальные процессы не начнут без разрешения писать в файл, пока он не выполнит все свои действия и не вызовет flock($f, lock un) или не закроет файл. Откуда такая уверенность? Дело в том, что если в данный момент наш процесс не единственный претендент на запись, операционная система просто не выпустит его из "внутренностей" функции flock() , т. е. не допустит его продолжения, пока процесс-писатель не станет единственным. Момент, когда процесс, использующий исключительную блокировку, становится активным, знаменателен еще и тем, что все остальные процессы-писатели ожидают (все в той же функции flock() ), когда же он, наконец, закончит свою работу с файлом. Как только это произойдет, операционная система выберет следующий исключительный процесс, и т. д. Что ж, давайте теперь рассмотрим, как в общем случае должен быть устроен процесс-писатель, желающий установить для себя исключительную блокировку (листинг 15.2). IJTiicTW Модель процесса с исключительной блокировкой <? инициализация . . . $f=fopen($f,"a+") or die("Не могу открыть файл на запись!"); flock($f,LOCK EX); ждем, пока не станем единственн1ми В этой точке можем быть уверен:, что только эта программа работает с файлом ( Замечание Зачем мы используем fflush() перед тем, как разблокировать файл? Все очень просто: отключение блокировки не ведет к сбросу внутреннего файлового буфера, т. е. некоторые изменения могут быть "сброшены" в файл уже после того, как блокировка будет снята. Мы, разумеется, этого не хотим, вот и заставляем PHP принудительно записать все изменения на диск. ( Совет ) Устанавливайте исключительную блокировку, когда вы собираетесь изменять файл. Всегда используйте при этом режим открытия r, r+ или a+. Никогда не применяйте режим w. Снимайте блокировку так рано, как только сможете, и не забывайте перед этим вызвать fflush() . Разделяемая блокировка Мы решили ровно половину нашей задачи. Действительно, теперь данные из нескольких процессов-писателей не будут перемешиваться, но как быть с читателями? А вдруг процесс-читатель захочет прочитать как раз из того места, куда пишет процесс-писатель? В этом случае он, очевидно, получит "половинчатые" данные. То есть, данные неверные. Как же быть? Существуют два метода обхода этой проблемы. Первый - это использовать все ту же исключительную блокировку. Действительно, кто сказал, что исключительную . . . fflush($f); запис1ваем все изменения на диск flock($f,LOCK UN); говорим, что больше не будем работать с файлом fclose($f); Завершение . . . ?> Заметьте, что при открытии файла мы использовали не деструктивный режим w (который удаляет файл, если он существовал), а более "мягкий" - a+. Это неспроста. Посудите сами: удаление файла идеологически есть изменение его содержимого. Но мы не должны этого делать до получения исключительной блокировки (вспомните пример со светофором)! Поэтому, если вам нужно обязательно каждый раз стирать содержимое файла, ни в коем случае не используйте режим открытия w - применяйте a+ и функцию ftruncate() , описанную выше. Например: $f=fopen($f,"a+") or die("Не могу открыть файл на запись!"); flock($f,LOCK EX); ждем, пока не станем единственн1ми ftruncate($f,0); очишаем все содержимое файла 0 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 187 188 189 |