Подтвердить что ты не робот

Должен LOCK_EX для чтения и записи быть атомарным?

file_put_contents ( "file", "data", LOCK_EX )

для записи (что означает - блокировка и запись в режиме "Сохранить" )

file_get_contents ( "file", LOCK_EX )

для чтения (что означает - захват блокировки, а затем чтение)

будет ли это исключение? поднять ошибку? блокировать до блокировки? или по крайней мере - , если он? есть ли вероятность того, что php будет вести себя как этот день?

EDIT: я знаю, что можно использовать переименование - я бы хотел узнать ответ на этот вопрос...

4b9b3361

Ответ 1

Поскольку этот ответ длинный, здесь резюме: Нет, file_get_contents() не является атомарным, так как оно не соблюдает консультативные блокировки.

О блокировке файлов в PHP:

В PHP, хотя на платформе * nix блокировка файловой системы является только рекомендательной. Per документы (Emphasis mine):

PHP поддерживает переносимый способ блокировки полных файлов в виде сообщений (что означает, что все программы доступа должны использовать тот же способ блокировки или не работать). По умолчанию эта функция блокируется до тех пор, пока не будет получен требуемый замок; это можно контролировать (на платформах, отличных от Windows) с опцией LOCK_NB, описанной ниже.

Итак, если все процессы, которые обращаются к файлу, используют этот метод блокировки, вы в порядке.

Однако, если вы пишете статический HTML файл с разумным веб-сервером, блокировка будет проигнорирована. В середине записи, если запрос приходит, Apache будет обслуживать частично написанный файл. Блокировки не будут влиять на другой процесс, считывающий блокировку.

Единственное реальное исключение - если вы используете специальную опцию mount -o mand в файловой системе, чтобы включить обязательную блокировку (но это не очень сильно используется и может иметь ограничение производительности).

Прочитайте File Locking для получения дополнительной информации. А именно раздел под Unix:

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

Итак, в заключение, использование LOCK_EX создаст консультативную блокировку файла. Любая попытка прочитать файл блокируется, только если читатель уважает и/или проверяет блокировку. Если они этого не сделают, блокировка будет проигнорирована (поскольку это может быть).

Попробуйте. В одном процессе:

file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
    sleep(10);
    fseek($f, 0);
    var_dump(fgets($f, 4048));
    flock($f, LOCK_UN);
}
fclose($f);

И пока он спит, назовите это:

$f = fopen('test.txt', 'a+');
fwrite($f, 'foobar');
fclose($f);

Выход будет foobar...

О file_get_contents в частности:

К вашему другому конкретному вопросу, во-первых, нет параметра LOCK_EX для file_get_contents. Поэтому вы не можете передать это.

Теперь, глядя на исходный код, мы можем увидеть функцию file_get_contents, определенную в строке 521. Нет вызовов на внутренняя функция php_stream_lock, как это бывает при передаче file_put_contents('file', 'txt', LOCK_EX);, определенных в строке 589 того же файла.

Итак, давайте протестируем его, будем ли мы:

В файле file1.php:

file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
    sleep(10);
    fseek($f, 0);
    var_dump(fgets($f, 4048));
    flock($f, LOCK_UN);
}
fclose($f);

В файле2.php:

var_dump(file_get_contents('test.txt'));

При запуске file2.php немедленно возвращается. Так что нет, не кажется, что file_get_contents соблюдает блокировки файлов вообще...

Ответ 2

Теория вопросов гораздо лучше работает Программисты, чем здесь.

В этот момент PHP не поддерживает блокировку атомного файла.

Проще говоря, PHP не поддерживает объединенный fopen и flock, поэтому всегда будет небольшое окно возможностей для другого процесса для блокировки файла, который ваш процесс также открыл, прежде чем ваш процесс сможет заблокировать его.

Сказав, что flock будет по умолчанию блокироваться до тех пор, пока блокировка не будет выпущена. Имейте в виду, что примечание ircmaxell о консультативных блокировках на Linux/BSD.

Примечание. Для процесса чтения вы можете сделать это LOCK_SH вместо LOCK_EX, чтобы несколько потоков считывателей могли одновременно заблокировать его. Запись всегда должна выполняться с использованием LOCK_EX или повреждения данных риска.

Примечание 2: предыдущее примечание работает, потому что вы можете получать только общие блокировки, если нет эксклюзивных блокировок, но исключительная блокировка требует, чтобы блокировки не были доступны до блокировки.