1. 程式人生 > 程式設計 >php 中的訊號處理操作例項詳解

php 中的訊號處理操作例項詳解

本文例項講述了php 中的訊號處理操作。分享給大家供大家參考,具體如下:

首先我們需要了解幾個函式

pcntl_signal 安裝訊號處理器,也就是當指定訊號發生時,呼叫函式。
pcntl_alarm 指定秒數後向程序傳送SIGALRM訊號。
posix_getpid 返回當前程序id
posix_kill 給指定程序傳送訊號

一些常用的訊號說明

SIGHUP
本訊號在使用者終端連線(正常或非正常)結束時發出,通常是在終端的控制程序結束時,
通知同一session內的各個作業,這時它們與控制終端不再關聯。

SIGINT
程式終止(interrupt)訊號,在使用者鍵入INTR字元(通常是Ctrl-C)時發出。

SIGQUIT
和SIGINT類似,但由QUIT字元(通常是Ctrl-/)來控制;程序在因收到SIGQUIT退出時會產生core檔案,
在這個意義上類似於一個程式錯誤訊號。

SIGKILL
用來立即結束程式的執行。本訊號不能被阻塞、處理和忽略。如果管理員發現某個程序終止不了,可嘗試傳送這個訊號。

SIGTERM
程式結束(terminate)訊號,與SIGKILL不同的是該訊號可以被阻塞和處理。通常用來要求程式自己正常退出,
shell命令kill預設產生這個訊號。如果程序終止不了,我們才會嘗試SIGKILL。

SIGUSR1
留給使用者使用

SIGUSR2
留給使用者使用

SIGALRM
時鐘定時訊號,計算的是實際的時間或時鐘時間。alarm函式使用該訊號。

SIGCHLD
子程序結束時,父程序會收到這個訊號。

例1:

<?php
declare(ticks = 1);
//訊號處理函式
function sig_func() {
  echo "child exit \r\n";
}
//設定訊號處理器
pcntl_signal(SIGCHLD,'sig_func');
$pid = pcntl_fork();
if($pid == -1) {
  die('fork error');
} else if ($pid) {
  pcntl_wait($status);
} else {
  echo "child... \r\n";
  exit;
}

當子程序退出時,會向父程序傳送SIGCHLD訊號,我們通過設定訊號處理器,成功的處理訊號。

例2:

<?php
declare(ticks = 1);
//訊號處理函式
function sig_func($signo) {
  switch($signo) {
    case SIGCHLD: {
      echo "child SIGCHLD \r\n";
      break;
    }
    case SIGTERM: {
      echo "child SIGTERM \r\n";
      break;
    }
    default:
      //處理所有其他訊號
      break;
  }
}
//設定訊號處理器
pcntl_signal(SIGCHLD,'sig_func');
//設定訊號處理器
pcntl_signal(SIGTERM,'sig_func');
$pid = pcntl_fork();
if($pid == -1) {
  die('fork error');
} else if ($pid) {
  pcntl_wait($status);
} else {
  sleep(3);
  echo "child \r\n";
  sleep(3);
  posix_kill(getmypid(),SIGTERM);
  exit;
}

父程序等待子程序的退出,子程序等待3秒後輸出child,再等待3秒後向自身傳送結束程式訊號。

例3:

<?php
declare(ticks = 1);
//訊號處理函式
function sig_func($signo) {
  switch($signo) {
    case SIGCHLD: {
      echo "child SIGCHLD \r\n";
      break;
    }
    /*這裡要把處理SIGTERM訊號的程式碼註釋掉
    case SIGTERM: {
      echo "child SIGTERM \r\n";
      break;
    }*/
    default:
      //處理所有其他訊號
      break;
  }
}
//設定訊號處理器
pcntl_signal(SIGCHLD,'sig_func');
//設定訊號處理器,也註釋掉
//不然當父程序發向子程序傳送SIGTERM訊號時,子程序不會退出,還會繼續執行
//我們的訊號處理函式把SIGTERM給忽略了
//pcntl_signal(SIGTERM,'sig_func');
$pid = pcntl_fork();
if($pid == -1) {
  die('fork error');
} else if ($pid) {
  sleep(30);
  posix_kill($pid,SIGTERM);
} else {
  $cnt = 0;
  for(;;) {
    sleep(3);
    echo $cnt,'-';
    ++$cnt;
  }
  exit;
}

父程序在等待30秒後,向子程序傳送SIGTERM結束程式訊號。如果我們設定了SIGTERM訊號的處理器,並且在自定義訊號處理器中並沒有殺死該程序,則該子程序會一直執行下去。

pcntl_signal()函式僅僅是註冊訊號和它的處理方法,真正接收到訊號並呼叫其處理方法的是pcntl_signal_dispatch()函式。

例4:

<?php
//使用ticks需要PHP 4.3.0以上版本
//declare(ticks = 1);
function sig_func() {
  echo "SIGALRM \r\n";
}
//設定訊號處理器
pcntl_signal(SIGALRM,'sig_func');
pcntl_alarm(3);

通過函式pcntl_alarm()3秒後給程序傳送SIGALRM訊號,但訊號處理函式並未呼叫。
原因是我們註釋了declare(ticks = 1);這段程式碼,而又沒有呼叫pcntl_signal_dispatch()函式。

declare(ticks = 1);表示每執行一條低階指令,就檢查一次訊號,如果檢測到註冊的訊號,就呼叫其訊號處理器。但是這種處理方式效率很低,建議在程式碼迴圈中通過pcntl_signal_dispatch()來處理訊號。

<?php
//使用ticks需要PHP 4.3.0以上版本
//declare(ticks = 1);
function sig_func() {
  echo "SIGALRM \r\n";
}
//設定訊號處理器
pcntl_signal(SIGALRM,'sig_func');
pcntl_alarm(3);
//因為3秒後pcntl_alarm函式才會給程序傳送SIGALRM訊號
//所以我們通過sleep函式等待3秒後,呼叫pcntl_signal_dispatch()來處理訊號
sleep(3);
pcntl_signal_dispatch();

pcntl_signal_dispatch()這個函式是PHP5.3以上才支援的,如果你的PHP版本大於5.3,建議使用這個方法呼叫訊號處理器。
5.3以下的版本需要在註冊訊號之前加上:declare(ticks = 1);

更多關於PHP相關內容感興趣的讀者可檢視本站專題:《PHP程序與執行緒操作技巧總結》、《PHP網路程式設計技巧總結》、《PHP基本語法入門教程》、《PHP陣列(Array)操作技巧大全》、《php字串(string)用法總結》、《php+mysql資料庫操作入門教程》及《php常見資料庫操作技巧彙總》

希望本文所述對大家PHP程式設計有所幫助。