PHPプログラミングにおけるロック


PHPプログラミングにおけるロック
最近『Linuxプロセスを理解する』というオープンソースの本を読んで、リンクしました.この本はlinuxの中のプロセスの概念を説明して、ロックとプロセス間の通信(IPC)に対していくつか総括があります.しかし、この本の記述言語はgolangで、普段はあまり使われていないので、概念に対応してphpのインタフェースを探したいと思っています.
ファイルロック
フルネームはadvisory file lockで、本には言及されています.このようなロックは、mysql、php-fpmが起動するとpidファイルにプロセスidが記録されます.このファイルがファイルロックです.
このロックは、crontabを使用する場合など、プロセスを繰り返し実行することを防止します.たとえば、1分ごとにタスクを実行することを制限しますが、このプロセスの実行時間は1分を超える可能性があります.プロセスロックを使用しないで競合を解決すると、2つのプロセスが一緒に実行されると問題が発生します.
PIDファイルロックを使用すると、プロセスが自分に停止または再起動信号を送るのを容易にするメリットがあります.例えばphp-fpmを再起動するコマンドは
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
USR2信号をpidファイルに記録するプロセスに送信し、信号はプロセス通信に属し、別のページを開く.
phpのインタフェースはflockで、ドキュメントは比較的詳細です.定義を見てみましょう
  • bool flock ( resource $handle , int $operation [, int &$wouldblock ] )はファイルシステムポインタであり、典型的にはfopen()によって作成されるresource(リソース)である.これはflockを使用してファイルを開く必要があることを意味します.
  • $handleは動作タイプである.
  • $operationロックがブロックする場合、この変数は1に設定される.

  • なお、この関数のデフォルトはブロックであり、operationにbitmask &$wouldblockを追加しなければならない.次にテストします.
    $pid_file = "/tmp/process.pid";
    $pid = posix_getpid();
    $fp = fopen($pid_file, 'w+');
    if(flock($fp, LOCK_EX | LOCK_NB)){
        echo "got the lock 
    "; ftruncate($fp, 0); // truncate file fwrite($fp, $pid); fflush($fp); // flush output before releasing the lock sleep(300); // long running process flock($fp, LOCK_UN); // } else { echo "Cannot get pid lock. The process is already up
    "; } fclose($fp);
    LOCK_NBとして保存し、process.phpを実行します.この場合、php process.php &を再度実行すると、エラーメッセージが表示されます.flockにも共有ロックがある、php process.php.
    反発ロックと読み書きロック
    syncモジュール内のMutex
    Mutexは組み合わせ語で、mutual exclusionです.peclでsyncモジュール、LOCK_SHをインストールします.ドキュメントのSyncMutexには2つの方法しかありません.lockとunlock、コードテストに直接行きましょう.IDEで書かれていないので、csは異常に醜いので、無視してください.
    $mutex = new SyncMutex("UniqueName");
    
    for($i=0; $i<2; $i++){
        $pid = pcntl_fork();
        if($pid <0){
            die("fork failed");
        }elseif ($pid>0){
            echo "parent process 
    "; }else{ echo "child process {$i} is born.
    "; obtainLock($mutex, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed
    "; } function obtainLock ($mutex, $i){ echo "process {$i} is getting the mutex
    "; $res = $mutex->lock(200); sleep(1); if (!$res){ echo "process {$i} unable to lock mutex.
    "; }else{ echo "process {$i} successfully got the mutex
    "; $mutex->unlock(); } exit(); }
    pecl install sync、run mutex.php、output isとして保存
    parent process 
    parent process 
    child process 1 is born. 
    process 1 is getting the mutex 
    child process 0 is born. 
    process 0 is getting the mutex 
    process 1 successfully got the mutex 
    Child 0 completed
    process 0 unable to lock mutex. 
    Child 0 completed

    ここでサブプロセス0と1は必ずしも誰が前にいるとは限らない.しかし、いつも鍵がかかっていないものがあります.ここでphp mutex.phpのパラメータはmillisecondであり、ブロックの時間長を表し、-1は無限ブロックである.
    syncモジュールの読み書きロックSyncMutex::lock(int $millisecond)の方法は似ていて、SyncReaderWriterreadlockreadunlockwritelockwriteunlock、ペアで現れてもいいです.テストコードを書いていません.Mutexのコードと一致するはずです.ロックを交換すればいいです.
    syncモジュールのEvent
    感覚はgolangのCondと比較して、wait()が閉塞し、fire()がEvent閉塞のプロセスを呼び覚ます.Condを紹介した良い文があり、Condが鍵の固定的な使い方であることがわかります.SyncEventも同じです.phpドキュメントの例によると、fire()メソッドはwebアプリケーションで使用できるようです.
    テストコード
    for($i=0; $i<3; $i++){
        $pid = pcntl_fork();
        if($pid <0){
            die("fork failed");
        }elseif ($pid>0){
            //echo "parent process 
    "; }else{ echo "child process {$i} is born.
    "; switch ($i) { case 0: wait(); break; case 1: wait(); break; case 2: sleep(1); fire(); break; } } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed
    "; } function wait(){ $event = new SyncEvent("UniqueName"); echo "before waiting.
    "; $event->wait(); echo "after waiting.
    "; exit(); } function fire(){ $event = new SyncEvent("UniqueName"); $event->fire(); exit(); }

    ここではわざとfire()を1つ少なく書くので、プログラムがブロックされ、fire()が一度に1つのプロセスだけを呼び覚ますことを証明します.
    pthreadsモジュール
    Mutex、Cond、Poolも見たようです.見る暇がなくて、見終わってから補充します.
    しんごうりょう
    syncモジュールにおける信号量SyncSemaphore文書には、Semaphoreは一度に複数のプロセス(またはスレッド)によって得られるが、Mutexは一度に1つしか得られない点で、Mutexとは異なる点が示されている.したがって、SyncSemaphoreの構造関数では、信号量がどのくらいのプロセスで得られるかを指定するパラメータがある.public SyncSemaphore::__construct ([ string $name [, integer $initialval [, bool $autounlock ]]] )はこの$initialval(initial value)です
    $lock = new SyncSemaphore("UniqueName", 2);
    
    for($i=0; $i<2; $i++){
        $pid = pcntl_fork();
        if($pid <0){
            die("fork failed");
        }elseif ($pid>0){
            echo "parent process 
    "; }else{ echo "child process {$i} is born.
    "; obtainLock($lock, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed
    "; } function obtainLock ($lock, $i){ echo "process {$i} is getting the lock
    "; $res = $lock->lock(200); sleep(1); if (!$res){ echo "process {$i} unable to lock lock.
    "; }else{ echo "process {$i} successfully got the lock
    "; $lock->unlock(); } exit(); }

    このとき、両方のプロセスがロックされます.
    Sysvsemモジュールにおける信号量
  • sem_get信号量
  • を作成する.
  • sem_remove削除信号量(一般的には使用しない)
  • sem_acquire信号量
  • の取得を要求する.
  • sem_release信号量を解放する.sem_acquireとペアで使用します.
  • $key = ftok('/tmp', 'c');
    $sem = sem_get($key);
    
    for($i=0; $i<2; $i++){
        $pid = pcntl_fork();
        if($pid <0){
            die("fork failed");
        }elseif ($pid>0){
            //echo "parent process 
    "; }else{ echo "child process {$i} is born.
    "; obtainLock($sem, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed
    "; } sem_remove($sem); // finally remove the sem function obtainLock ($sem, $i){ echo "process {$i} is getting the sem
    "; $res = sem_acquire($sem, true); sleep(1); if (!$res){ echo "process {$i} unable to get sem.
    "; }else{ echo "process {$i} successfully got the sem
    "; sem_release($sem); } exit(); }

    ここで問題があります.sem_acquire()の2番目のパラメータ$nowaitのデフォルトはfalseで、ブロックされています.trueとして、ロックが失敗した場合、後のsem_releasePHP Warning: sem_release(): SysV semaphore 4 (key 0x63000081) is not currently acquired in /home/jason/sysvsem.php on line 33に警告するので、ここでのrelease操作はロックを取得した場合に実行しなければならない.前のいくつかの例ではこの問題はなく、ロックを取得していなくてもreleaseを実行してもエラーは報告されない.もちろんペアで現れ、ロックが得られた場合にreleaseするのが望ましい.
    また、ftokという方法のパラメータは、最初はexisting、accessableのファイルでなければならず、一般的にプロジェクトのファイルを使用し、2番目は単一文字文字文字列である必要があることを説明する必要があります.intを返します.
    出力は
    parent process 
    parent process 
    child process 1 is born. 
    process 1 is getting the mutex 
    child process 0 is born. 
    process 0 is getting the mutex 
    process 1 successfully got the mutex 
    Child 0 completed
    process 0 unable to lock mutex. 
    Child 0 completed

    最後に、もし文の中に間違いがあったら、大神に指摘してもらいたい.菜鳥の進歩を助けてください.ありがとうございました.