| |
овольно-таки неудачен, и вот по какой причине. Представьте, что
про-
цессов-читателей много, а писателей — мало, и к тому же писатели еще и
вызывают-
ся, скажем, раз в пару минут, а не постоянно, как читатели. В случае
использования
исключительной блокировки для процессов-читателей, довольно интенсивно обра-
щающихся к файлу, мы очень скоро получим целый их рой, висящий, недовольно
гудя, в очереди, пока очередному процессу разрешат читать. Но ведь никакой
"ава-
рии" не случится, если один и тот же файл будут читать и сразу все процессы
этого
роя, правда? Ведь чтение из файла его не изменяет. Итак, предоставив
исключитель-
ную блокировку для читателей, мы потенциально получаем проблемы с производи-
тельностью, перерастающие в катастрофу, когда процессов-читателей становится
больше некоторого определенного порога.
Второй (и лучший) способ подразумевает использование разделяемой блокировки.
Процесс, который устанавливает этот вид блокировки, будет приостановлен только
в
одном случае: когда активен другой процесс, установивший исключительную блоки-
ровку. В нашем примере процессы-читатели будут "поставлены в очередь" только
тогда, когда активизируется процесс-писатель. И это правильно. Посудите сами:
за-
чем зажигать красный свет на перекрестке, если поперечного движения заведомо
нет?
Теперь давайте посмотрим на разделяемую блокировку читателей с точки зрения
процесса-писателя. Что он должен делать, если кто-то читает из файла, в который
он
как раз собирается записывать? Очевидно, он должен дождаться, пока читатель не
закончит работу. Иными словами, вызов flock($f,LOCK_EX) обязан подождать,
пока активна хотя бы одна разделяемая блокировка. Это и происходит в
действитель-
ности.
Возможно, вам на ум пришла аналогия с перекрестком, по одной дороге кото-
рого движется почти непрерывный поток машин, и поперечное движение при
этом блокируется навсегда, — так что у водителей нет никаких шансов про-
биться через сплошной поток. В реальном мире это действительно иногда про-
исходит (потому-то любой светофор всегда представляет собой исключитель-
ную блокировку), но только не в мире PHP. Дело в том, что, если почти всегда
активна разделяемая блокировка, операционная система все равно так рас-
пределяет кванты времени, что в некоторые из них можно "включить" исключи-
тельную блокировку. То есть "поток машин" становится не сплошным, а с "про-
белами" — ровно такого размера, чтобы в них могли "прошмыгнуть" машины,
едущие в перпендикулярном направлении.
В листинге 15.3 представлена модель процесса, использующего разделяемую блоки-
ровку.
Листинг 15.3. Модель процесса с разделяемой блокировкой
Глава 15. Работа с файлами 265
// инициализация
// . . .
$f=fopen($f,"r") or die("Не могу открыть файл на чтение!");
flock($f,LOCK_SH); // ждем, когда процессы-писатели угомонятся
// В этой точке мы можем быть уверены, что эта программа работает
// с файлом, когда ни одна другая программа в него не пишет
// . . .
flock($f,LOCK_UN); // говорим, что мы больше не будем работать с файлом
fclose($f);
// Завершение
// . . .
?>
Устанавливайте разделяемую блокировку, когда вы собираетесь только читать
из файла, не изменяя его. Всегда используйте при этом режим открытия r, и
никакой другой. Снимайте блокировку так рано, как только сможете.
Блокировки с запретом "подвисания"
Как следует из описания функции flock(), к ее второму параметру можно приба-
вить константу LOCK_NB для того, чтобы функция не ожидала, когда программа мо-
жет "двинуться в путь", а сразу же возвращала управление в основную программу.
Это может пригодиться, если вы не хотите, чтобы ваш сценарий бесполезно
простаи-
вал, ожидая, пока ему разрешат обратиться к файлу. В эти моменты, возможно,
луч-
ше будет заняться какой-нибудь полезной работой — например, почистить времен-
ные файлы, память, или же просто сообщить пользователю, что файл заблокирован,
чтобы он подождал и не думал, что программа зависла. Вот пример использования
исключительной блокировки в совокупности с LOCK_NB:
$f=fopen("file.txt","a+");
while(!flock($f,LOCK_EX+LOCK_NB)) {
echo "Пытаемся получить доступ к файлу ";
sleep(1); // ждем 1 секунду
}
// Работаем
Эта программа основывается на том факте, что выход из fl
|
|