web-dev-qa-db-ja.com

PHP相互排除(ミューテックス)

PHPでのロックに関するいくつかのテキストを読んでください。
それらはすべて、主に http://php.net/manual/en/function.flock.php に直接送信されます。

このページでは、ハードディスク上のファイルを開く方法について説明しています。

本当にそうですか?つまり、これはロックを非常に高価にします-つまり、ロックするたびにハードディスクにアクセスする必要があります)=

もう楽しいニュースで私を慰めることができますか?

編集:

私がここに持っているいくつかの返事のために、私はこれを聞きたいです。
私のスクリプトは1つのスレッドだけで実行されますか、それとも複数のスレッドで実行されますか?それが1つである場合、私は明らかにミューテックスを必要としないからです。簡潔な答えはありますか?

私がやろうとしていること

Ircmaxellからの質問。
これは物語です:

私は2つのftpサーバーを持っています。自分のWebサイトで、オンラインになっているオンラインユーザーの数を表示できるようにしたいと思います。
したがって、これらのftpサーバーは統計を特定のPHPスクリプトページに「POST」する」と思いました。このページのURLが「 http ://mydomain.com/update.php "。

ウェブサイトのメインページ( " http://mydomain.com/index.php ")に累積統計(オンラインユーザー)を表示します。

それでおしまい。

私の問題は、あるftpサーバーが統計を更新し、別のftpサーバーも更新するときに、情報が混在するかどうかわからないことです。
マルチスレッドの場合と同様。 2つのスレッドは、同時にいくつかの「int」変数を増やします。それらの間で同期しない限り、期待どおりには発生しません。
では、問題はありますか?そうですね?

考えられる解決策

一日中一生懸命考えて、ここにアイデアがありますので、ぜひご意見をお聞かせください。
前述のように、これらのftpサーバーは60秒に1回統計を投稿します。
このファイル「stats.php」を作成することを考えています。
これは、ftpサーバーがアクセスする更新スクリプト( "update.php")と、訪問者がオンラインになっているユーザーの数を確認できる "index.php"ページに含まれます。
これで、ftpサーバーが更新されると、「update.php」のスクリプトが「stats.php」を新しい累積統計で変更します。
最初に「stats.php」に含まれている統計を読み取り、次に蓄積してから、そのファイルを書き換えます。

私が間違っていなければ、PHPはファイル( "stats.php")が変更されたことを検出し、新しいファイルをロードします。正しいですか?

23
Poni

ええと、ほとんどのPHPは異なるプロセススペースで実行されます(スレッドの実装はほとんどありません)。簡単なものは群れです。すべてのプラットフォームで動作することが保証されています。

ただし、サポートでコンパイルする場合は、Semaphore拡張機能などの他のいくつかのものを使用できます。 (Compile PHP with --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がすべてのリクエストをシリアルに処理し、1つのプロセス(および1つのスレッド)のみがすべてのリクエストを処理することは非常にまれです。CGIを使用している場合、デフォルトでマルチプロセスになります。 FastCGIを使用している場合は、マルチプロセスおよびマルチスレッドである可能性があります。Apacheでmod_phpを使用している場合は、ワーカーの種類によって異なります。

  1. mpm_workerはマルチプロセスとマルチスレッドの両方であり、プロセスの数はServerLimit変数によって指定されます。
  2. プリフォークはマルチプロセスになります
  3. パーチャイルドもマルチプロセスになります

編集:2番目に編集された質問に答えるには:

とても簡単です。ファイルに保存します。

_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;
}
_
31
ircmaxell

問題は、FTPサーバーがPOSTでupdate.phpファイルにプッシュしている統計をどこに保存しますか?それがローカルファイルの場合、2番目の投稿のircmaxellがあなたに答えたよりも。これはミューテックス(セマフォ関数)でも実行できます。別の解決策は、MySQL MyISAMテーブルを使用して統計を保存し、update info_table set value = value + 1のようなものを使用することです。テーブルをロックし、リクエストをシリアル化する必要があります。問題ありません。

1
Milen Boev

私は最近、PHPのflock関数を使用して、ミューテックスのようなメカニズムの独自の単純な実装を作成しました。もちろん、以下のコードは改善できますが、ほとんどのユースケースで機能します。

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;
}
0
Mark Baaijens

はい、そうです。PHPはApacheによって実行され、Apacheは実行スレッドを最適と見なすように編成できます(さまざまなワーカーモデルを参照)。したがって、リソースにアクセスする場合は、一度に、ファイルにロックするか(たとえば、cronジョブを処理する場合に適しています)、データを処理する場合は、データベーストランザクションメカニズム、ACID機能、およびデータベースリソースのロックに依存します。

0
Palantir