English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

PHPプロセス通信の基礎:シグナル

シグナル通信を使用すると、kill -l で現在のシステムのシグナルタイプを確認してください。
各シグナルが持つ詳細な意味について、この記事をご覧ください:https://ja.oldtoolbag.com/article/106040.htm
シグナルを使用する場合、php --バージョンを確認して、現在のPHPのバージョンを確認してください。プロセス間のシグナル通信を行う方法を選定しました。

[root@roverliang ipc]# php --バージョン
PHP 5.6.24 (cli) (ビルド: Aug 15 2016 19:14:02)
著作権(c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

pcntl_signal_dispatch 関数を使用するには、PHP バージョン (PHP 5 >= 5.3.0, PHP 7)

PHPバージョンが以下のバージョン以下である場合、5.3.大手企業ではこのバージョンよりも低いバージョンが使用されることがあります。その場合、declare(ticks=1), 1 つの低レベル命令の実行ごとに、
信号が発生するかどうかを検出します。詳細は https://ja.oldtoolbag.com/article/48340.htm

公式サイトの説明によると、Tick(タイムキック)は、declare ブロック内でエンジンが N 条可計の低レベル命令を実行したときに発生するイベントです。N の値は、declare 内の directive 部分で ticks=N で指定されます。

低レベル文とは何でしょうか:以下のコードを参照してください:

  for ($i = 0; $i < 3; $i++) {
    echo $i.PHP_EOL;
  }

それでは、この for ループには 3 つの低レベル命令が含まれています。$i を 1 つ出力するたびに、既に登録されたイベントが発生したかどうかを検出します。このようにして、効率は非常に低いです。したがって、PHPバージョンが以下のバージョン以上である場合、検出を行います5.3 。それでは、pcntl_signal_dispatch を使用して信号派送を行います。

マスタープロセスが起動する際に、いくつかの信号処理関数を登録します。

/**
 * @param $signal 信号
 */
function signalHandal($signal)
{
  switch ($signal) {
    case SIGINT:
      //何かを行います
      break;
    case SIGHUP:
      //何かを行います
      break;
    default :
      //何かを行います
      break;
  }
}

その後、信号処理器と信号処理関数をバインドします:

//異なる信号に応じて、異なる信号処理器をインストールします。
pcntl_signal(SIGINT, 'signalHandal');
pcntl_signal(SIGHUP, 'signalHandal');
pcntl_signal(SIGUSR1, 'signalHandla');

子プロセスで信号を監視し、その信号が発生した場合、事前にインストールされた信号処理関数を呼び出します。

//信号を割り当てます。
pcntl_signal_dispatch($signal);

考え方を整理しましょう:
1、信号発生時に処理する必要のあるイベントの関数を定義します。
2、信号と信号処理関数をバインドし、信号インストールと呼びます。
3、信号を監視または配信し、既にインストールされた信号が呼び出されます。

上記の信号概念を理解したら、デモを見てみましょう:

<?php
$parentpid = posix_getpid();
echo "parent progress pid:{$parentpid}\n";
//シグナルハンドラ関数を定義します
function sighandler($signal) {
  if ($signal == SIGINT) {
    $pid = getmypid();
    exit("{$pid} process, Killed!".PHP_EOL);
  }
}
//php version < 5.3 .低レベルコマンドの実行ごとに、シグナルが発生していないか確認します。効率が非常に悪いです。
//declare(ticks=1);
$child_list = [];
//シグナルハンドラを登録します。シグナルが発信された場合、定義された関数を呼び出します。
pcntl_signal(SIGINT, 'sighandler');
for($i = 0; $i < 3; $i++) {
  $pid = pcntl_fork();
  if ($pid == 0) {
    //子プロセス
    while (true) {
      //既にインストールされたシグナルハンドラを呼び出し、dispatchingに新しいシグナルが待っているかを検出するために
      pcntl_signal_dispatch();
      echo "I am child: ".getmypid(). " and i am running !".PHP_EOL;
      sleep(rand(1,3));
    }
  }
    $child_list[] = $pid;
  } else {
    die('fork fail!'.PHP_EOL);
  }
}
sleep(5);
foreach ($child_list as $key => $pid) {
  posix_kill($pid, SIGINT);
}
sleep(2);
echo "{$parentpid} parent is end".PHP_EOL;