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

PHP взаимное исключение (мьютекс)

Прочитайте некоторые тексты о блокировке в PHP.
Все они, главным образом, обращаются к http://php.net/manual/en/function.flock.php.

Эта страница рассказывает об открытии файла на жестком диске.

Неужели это так? Я имею в виду, что это делает блокировку очень дорогой - это означает, что каждый раз, когда я хочу заблокировать, мне придется обращаться к жесткому диску) =

Может больше утешить меня восхитительной новостью?

Edit:

Из-за некоторых ответов, которые у меня есть, я хочу спросить об этом. Мой script будет работать только одним потоком или несколькими? Потому что если это один, то я, очевидно, не нуждаюсь в мьютексе. Есть ли сжатый ответ?

Что именно я пытаюсь сделать

Ответов на вопрос ircmaxell.
Это история:

У меня есть два ftp-сервера. Я хочу показать на своем веб-сайте, сколько онлайн-пользователей онлайн.
Итак, я думал, что эти ftp-серверы будут "POST" их статистики на определенную страницу PHP script. Предположим, что URL этой страницы " http://mydomain.com/update.php".

На главной странице сайта (http://mydomain.com/index.php") Я покажу кумулятивную статистику (онлайн-пользователи).

Что это.

Моя проблема в том, что я не уверен, что, когда один ftp-сервер обновляет свою статистику, а другой тоже делает это, информация будет смешанной.
Как при многопоточности; Два потока одновременно увеличивают некоторую переменную "int". Это произойдет не так, как ожидалось, если вы не синхронизируете между ними.
Итак, у меня будет проблема? Да, нет, может быть?

Возможное решение

Мы долго думаем об этом, у меня есть идея здесь, и я хочу, чтобы вы дали свое мнение.
Как сказано, эти ftp-серверы будут публиковать свою статистику каждые раз в 60 секунд.
Я думаю о том, что этот файл "stats.php".
Он будет включен при обновлении script, на котором серверы ftp переходят на страницу ( "update.php" ) и на страницу "index.php", где посетители видят, сколько пользователей находятся в сети.
Теперь, когда обновляется ftp-сервер, script на "update.php" будет изменять "stats.php" с новой совокупной статистикой.
Сначала он будет читать статистику, включенную в "stats.php", затем накапливается, а затем переписывать этот файл.

Если я не ошибаюсь, PHP обнаружит, что файл ( "stats.php" ) изменен и загружает новый. Правильно?

4b9b3361

Ответ 1

Ну, большая часть PHP работает в другом пространстве процесса (существует несколько реализаций потоков). Легкий - это стая. Это гарантировало работу на всех платформах.

Однако, если вы скомпилируете поддержку, вы можете использовать несколько других функций, таких как расширение Semaphore. (Скомпилируйте PHP с помощью --enable-sysvsem). Затем вы можете сделать что-то вроде (обратите внимание, что sem_acquire() должен блокировать. Но если он почему-то не может, он вернет false):

$sem = sem_get(1234, 1);
if (sem_acquire($sem)) {
    //successful lock, go ahead
    sem_release($sem);
} else {
    //Something went wrong...
}

Другими параметрами, которые у вас есть, являются MySQL блокировки уровня пользователя GET_LOCK('name', 'timeout') или создание собственного, используя что-то вроде APC или XCache (Примечание, это не было бы настоящей блокировкой, так как условия гонки могут быть созданы, когда кто-то другой получает блокировку между вашим проверкой и принятием блокировки).

Изменить: ответить на ваш отредактированный вопрос:

Все зависит от конфигурации вашего сервера. PHP Может быть запущен многопоточным (где каждый запрос обслуживается другим потоком), или может быть запущен многопроцессорный процесс (где каждый запрос обслуживается другим процессом). Все зависит от конфигурации вашего сервера...

ОЧЕНЬ редко, что PHP будет обслуживать все запросы поочередно, только один процесс (и один поток), обслуживающий все запросы. Если вы используете CGI, то он по-разному обрабатывается. Если вы используете FastCGI, это, вероятно, многопроцессорное и многопоточное. Если вы используете mod_php с Apache, это зависит от типа рабочего:

  • mpm_worker будет как многопроцессорным, так и многопоточным, с количеством процессов, продиктованных переменной ServerLimit.
  • prefork будет мультипроцессом
  • perchild будет также многопроцессором

Изменить: ответить на второй отредактированный вопрос:

Это довольно легко. Сохраните его в файле:

function readStatus() {
    $f = fopen('/path/to/myfile', 'r');
    if (!$f) return false;
    if (flock($f, LOCK_SH)) {
        $ret = fread($f, 8192);
        flock($f, LOCK_UN);
        fclose($f);
        return $ret;
    }
    fclose($f);
    return false;
}

function updateStatus($new) {
    $f = fopen('/path/to/myfile', 'w');
    if (!$f) return false;
    if (flock($f, LOCK_EX)) {
        ftruncate($f, 0);
        fwrite($f, $new);
        flock($f, LOCK_UN);
        fclose($f);
        return true;
    }
    fclose($f);
    return false;
}

function incrementStatus() {
    $f = fopen('/path/to/myfile', 'rw');
    if (!$f) return false;
    if (flock($f, LOCK_EX)) {
        $current = fread($f, 8192);
        $current++;
        ftruncate($f, 0);
        fwrite($f, $current);
        flock($f, LOCK_UN);
        fclose($f);
        return true;
    }
    fclose($f);
    return false;
}

Ответ 2

Вопрос: где вы будете хранить статистику, которую FTP-серверы нажимают с помощью POST в файл update.php? Если это локальный файл, на ваш ответ ответит ircmaxell во втором сообщении. Вы можете сделать это с помощью мьютекса - функции семафора. Другое решение - использовать таблицу MySQL MyISAM для хранения статистики и использовать что-то вроде update info_table set value = value + 1. Он должен блокировать таблицу и сериализовать ваши запросы, и у вас не будет проблем.

Ответ 3

Да, это правда, поскольку PHP запускается Apache, и Apache может организовать потоки выполнения, поскольку он считает, что лучше всего (см. разную модель рабочего). Поэтому, если вы хотите получить доступ к ресурсу по одному, вы либо блокируете файл (что хорошо, если вы имеете дело с заданиями cron, например), либо полагаетесь на механизм транзакций базы данных, функции ACID и блокировку ресурсов базы данных, если вы имеете дело с данными.

Ответ 4

Если вам нужна потоковая передача, вы серьезно относитесь к неправильному языку.

Ответ 5

Почему бы вам просто не записать файл обновления в имя файла на основе ipaddress входящего ftp-сервера. И файл php статистики просто читает и добавляет числовое содержимое обоих этих файлов вместе.

Ответ 6

Недавно я создал свою собственную простую реализацию мьютексоподобного механизма с использованием функции flock в PHP. Конечно, приведенный ниже код может быть улучшен, но он работает для большинства случаев использования.

function mutex_lock($id, $wait=10)
{
  $resource = fopen(storage_path("app/$id.lck"),"w");

  $lock = false;
  for($i = 0; $i < $wait && !($lock = flock($resource,LOCK_EX|LOCK_NB)); $i++)
  {
    sleep(1);
  }

  if(!$lock)
  {
    trigger_error("Not able to create a lock in $wait seconds");
  }

  return $resource;
}

function mutex_unlock($id, $resource)
{
  $result = flock($resource,LOCK_UN);
  fclose($resource);

  @unlink(storage_path("app/$id.lck"));

  return $result;
}

Ответ 7

PHP не поддерживает многопоточность, каждый запрос (и, следовательно, каждый PHP script) будет выполняться только в одном потоке (или даже процессе, в зависимости от того, как вы запускаете PHP).