php flock не блокирует файл
Проясните пожалуйста с flock
Новичок
Проясните пожалуйста с flock
1. Создал файл a.php вот такого содержания
Запускаю a.php и пока он спит запискаю b.php
По-идее, b.php не может записать что-то в файл, т.к. он заблокирован (LOCK_EX); он ждет свой очереди, т.е. у b.php ничего не получится до тех пор, пока a.php не поспит 20 секунд и не отключит лок. На деле получается совсем другое.
Проясните пожалуйста ситуацию с локами, а то запутался в том, как они работают.
MiksIr
miksir@home:
Духовность™
Продвинутый новичок
Ман: PHP поддерживает портируемый механизм запирания файлов целиком, который имеет рекомендательный характер (это означает, что все обращающиеся к файлу программы должны использовать такой же способ запирания файла, иначе запирание не сработает).
Если мы запустим эти два скрипта, то b.php будет ЖДАТЬ пока не снимется с файла блокировка файла a.php. Когда это случится, т.е. a.php запишет в файл, только после этого в файл запишет b.php. Итого в файл данные запишутся ПРАВИЛЬНО: сначала строка ‘aaa’, потом строка ‘bbb’.
Теперь если убрать блокировку из b.php
Новичок
А могу я как-нибудь просто проверить залочен в данный момент файл или нет. Просто в моём контексте нужно не дожидаться снятия и писать в файл, а немного по-другому, а имеено.
Php блокировка
Суть проблемы такова:
Есть база данных, используемая на сайте (например, база для регистрации пользователей, куда записывается их имя и email), она лежит в текстовом файле построчно (в дальнейшем, «file_base.dat».). Два пользователя активизируют сервер через командную строку в броузере, для ввода свох имен и email. Сервер отсылает их к скрипту. Оба пользователя «начинают движение» по скриптовому потоку (тексту php файла) сверху вниз, причем, Первый «бежит» на долю секунды быстрее Второго. Когда они достигают того места, где скрипт исполняет их запрос, движение по потоку останавливается, в их броузер выводится сгенерированная скриптом страница в виде html. Чтобы из file_base.dat прочитать данные, этот файл надо открыть на чтение (функция — @file), чтобы записать что-то в него, надо открыть на запись (функция — @fopen). В скрипте это выглядит так:
Суть ее такова: пока файл блокирован на чтение, пользователь, который хочет считать из него информацию, находится в цикле, то есть, как бы «стоит» на месте, не «бежит» дальше по тексту скрипта, ожидая, когда файл разблокируется на чтение. В итоге наш скрипт принимает такой вид:
Суть подхода, который предлагаем мы для решения этой проблемы такой:
Во время считывания из файла или записи в него данных, на сайте появляется текстовая строка с названием этого файла, когда из файла информация прочиталась или записалась, эта текстовая строка удаляется. Пока она есть, значит кто-то уже использует базу данных на чтение или запись, пользователь, который хочет обратиться к этой базе на чтение или запись, находится в цикле, ожидая пока текстовая строка исчезнет. Как только она исчезает, он читает или пишет в базу данных, сам при этом создавая такую же текстовую строку, тем самым препятствуя доступу двух и более пользователей к базе.
Для чего, на сайте создадим папку для хранения текстовых строк. Например, lock. Наш файл на сайте лежит в папке database, значит в папке lock надо создать папку database. Теперь, когда пользователь обращается к file_base.dat, для чтения или записи в него, абсолютный путь http://наш_сайт.ru/database/file_base.dat, в папке http://наш_сайт.ru/lock/database/ появляется файл-строка file_base.dat.tmp, абсолютный путь — http://наш_сайт.ru/lock/database/file_base.dat.tmp, закрывая доступ к file_base.dat, как только пользователь считал или записал информацию в наш файл-базу, текстовая строка file_base.dat.tmp удаляется, открывая доступ другим пользователям к file_base.dat.
В этой ситуации мы видим, что когда один пользователь достиг точки считывания с file_base.dat или, наоборот, другой пытается записать в file_base.dat информацию, нам ничего не страшно. Потому что, как в одном, так и в другом случае, появился маленький текстовый файл file_base.dat.tmp, который не дает ни одному ни другому совместно читать или писать в file_base.dat.
В нашем варианте есть одна «дыра», если вдруг пользователь обратился к базе данных, создав текстовую строку блокировки, незакончил как-бы цикл (свет погас и компьютер выключился), и эта текстовая блокирующая строка осталась лежать в папке lock, то наша программа «подвиснет», не давая никому пройти, из-за этого оставшегося флага.
Мы не стали усложнять функции проверкой на удаление этого файла-флага, а, просто ввели в функции его создающей, предел «подвисания» компьютера 10 секунд ($file_exist++; if($file_exist > 10)
Для проверки работоспособности этих функций запишите вручную в папку lock этот самый блокирующий файл file_base.dat.tmp, в нашем случае, это: http://наш_сайт.ru/lock/database/file_base.dat.tmp, тем самым, блокируя доступ к базе http://наш_сайт.ru/database/file_base.dat, запустите программу, обратитесь к базе, вы увидите, что флаг работает и броузер «стоит» на месте, удалите file_base.dat.tmp файл (разблокируя) и подвисание закончится.
PHP flock() не блокирует блокирование почему?
Я использую функцию flock(), чтобы проверить, запущен ли еще один экземпляр script, запустив блокировку временного файла, чтобы следующий экземпляр должен проверить, не заблокирован ли файл, иначе он останавливается
script работает без проблем при одновременном вызове файла дважды из разных браузеров, пока он ждет, если я одновременно открываю два экземпляра из одного и того же браузера, т.е. первый вызов получает блокировку, а второй – блокировка и закрытие
Я знаю, что могут быть другие способы проверить, работает ли экземпляр файла, но большинство из них сделает что-то, а затем отменит его, и в моем случае использование script может закончиться в любое время, так как это может занять много времени или превышать ограничение памяти или по какой-либо причине
Проблема заключалась в следующем:
вызов одного и того же script дважды с тем же URL-адресом из браузера будет выполняться через ту же самую процедуру и функцию flock(), не блокирующую работу на уровне процесса, заставляя второй script ждать
как пример вызова example.com/test.php
дважды приведет к тому, что два запроса будут работать в одном и том же процессе, добавив какую-либо случайную переменную, создаст отдельный процесс для каждого отдельного запроса, например
Запустите тот же самый script из командной строки дважды. Я был бы готов поспорить, что все работает отлично.
Скорее всего, ваш браузер ограничивает скорость соединения с сервером, позволяя только одному соединению одновременно с любым хостом. Тот факт, что вы получаете разные результаты в разных браузерах, указывает на то, что это не проблема PHP, поскольку PHP будет работать одинаково независимо от браузера, запрашивающего страницу.
flock — Портируемая консультативная блокировка файлов
Описание
flock() позволяет осуществить простую модель чтения/записи, которая может быть использована практически на любой платформе (включая большинство вариантов Unix и даже Windows).
В версиях PHP до 5.3.2 блокировка освобождалась также вызовом функции fclose() (которая также вызывается автоматически по завершении скрипта).
Список параметров
Также возможно добавить константу LOCK_NB в качестве битовой маски к любой из вышеуказанных операций, если вы не хотите ждать пока flock() получит блокировку.
Необязательный третий параметр будет установлен в 1, если блокировка будет блокирующей (код ошибки EWOULDBLOCK). (не поддерживается на Windows)
Возвращаемые значения
Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.
Список изменений
Версия | Описание |
---|---|
5.3.2 | Автоматическое снятие блокировки при закрытии было удалено. Снятие блокировки теперь всегда должно осуществляться вручную. |
Примеры
Пример #1 Пример использования функции flock()
Пример #2 Использование flock() с параметром LOCK_NB
Примечания
В Windows flock() использует обязательную (mandatory) блокировку вместо консультативной. Обязательная блокировка также поддерживается на Linux и операционных системах, основанных на System V с помощью стандартного механизма, который предоставляет системный вызов fcntl(): т.е. искомый файл должен иметь установленный бит доступа setgid и неустановленный бит группового выполнения. Для корректной работы этой схемы в Linux, файловая система также должна быть смонтирована с опцией mand.
Из-за того, что функции flock() необходим указатель на файл, вам может понадобиться воспользоваться специальным запирающим файлом для того, чтобы ограничить доступ к файлу, который вы намерены очищать, путём его открытия в режиме записи (используя «w» или «w+» в качестве аргумента функции fopen() ).
Присвоение другого значения аргументу handle в последующем коде отменит существующую блокировку.
В некоторых операционных системах flock() реализован на уровне процессов. При использовании многопоточных серверных API, таких как ISAPI, вы не можете полагаться на flock() для защиты ваших файлов от других PHP-скриптов, которые работают в параллельном потоке на том же сервере!
flock() не поддерживается на старых файловых системах вроде FAT и ее производных, так что всегда будет возвращать FALSE в этом окружении (это особенно касается пользователей Windows 98).
Вопрос по flock в php?
Появились вопросы по поводу записи данных в файл(ы) с использованием блокировок (flock).
Интересует ее надежность.
Скажем если два процесса одновременно захотят заблочить файл, что будет? Выстроится очередь или всетаки они оба пойдут писать в него?
Если она ненадежна, то подскажите более надежный вариант.
комментарий полезный, это несомненно, но
но семафоры на РНР — это как-то смешно…
использовал flock на РНР, вроде как надежно, сбоев не наблюдал.
On some operating systems flock() is implemented at the process level. When using a multithreaded server API like ISAPI you may not be able to rely on flock() to protect files against other PHP scripts running in parallel threads of the same server instance!
Ну и так в комментах жалобы на непонятное поведение например в Соляре или Фряхе.
akalend, а что смешного? Не самая часто используемая фича, ну так и веб-морду к БД Oracle не часто, кажется, пишут, а соответствующая поддержка есть.
Если ваш софт будет устанавливаться на стороннем окружении, то полагаться на flock определённо не стоит.
Если же вы пишете что-то для себя, и точно знаете, что например за рамки linux/freebsd + apache/nginx окружение не выйдет — можно смело использовать.
Если два процесса захотят заблочить файл — второй процесс будет ждать освобождения lock’а. Когда первый освободит lock, выполнение flock() во втором процессе завершится и процесс продолжит выполнение кода.
Более надёжный вариант на все случаи жизни — организовать lock самостоятельно через файлы/базу/memcache итп.