2012-10-04 35 views
4

這是完全可重複的代碼。PHP pcntl_signal回調不叫

<?php 
class console{ 
    public static function log($msg, $arr=array()){ 
     $str = vsprintf($msg, $arr); 
     fprintf(STDERR, "$str\n"); 
    } 
} 
function cleanup(){ 
    echo "cleaning up\n"; 
} 
function signal_handler($signo){ 
    console::log("Caught a signal %d", array($signo)); 
    switch ($signo) { 
     case SIGTERM: 
      // handle shutdown tasks 
      cleanup(); 
      break; 
     case SIGHUP: 
      // handle restart tasks 
      cleanup(); 
      break; 
     default: 
      fprintf(STDERR, "Unknown signal ". $signo); 
    } 
} 

if(version_compare(PHP_VERSION, "5.3.0", '<')){ 
    // tick use required as of PHP 4.3.0 
    declare(ticks = 1); 
} 

pcntl_signal(SIGTERM, "signal_handler"); 
pcntl_signal(SIGHUP, "signal_handler"); 

if(version_compare(PHP_VERSION, "5.3.0", '>=')){ 
    pcntl_signal_dispatch(); 
    console::log("Signal dispatched"); 
} 

echo "Running an infinite loop\n"; 
while(true){ 
    sleep(1); 
    echo date(DATE_ATOM). "\n"; 
} 

當我運行這個,我看到每秒的日期值。現在,如果我按Ctrl + C cleanup函數不被調用。實際上signal_handler未被調用。

這裏是示例輸出。

$ php testsignal.php 
Signal dispatched 
Running an infinite loop 
2012-10-04T13:54:22+06:00 
2012-10-04T13:54:23+06:00 
2012-10-04T13:54:24+06:00 
2012-10-04T13:54:25+06:00 
2012-10-04T13:54:26+06:00 
2012-10-04T13:54:27+06:00 
^C 
+0

甚至沒有單個評論 –

+1

錯誤。有你的評論。 ;) – hakre

+0

'version_compare()'中的PHP版本號與它之後的註釋之間存在差異 - 你會修復嗎? – halfer

回答

8

CTRL+C火災SIGINT,你沒有爲安裝的處理程序:

<?php 
... 
function signal_handler($signo){ 
... 
    case SIGINT: 
     // handle restart tasks 
     cleanup(); 
     break; 
... 
} 
... 
pcntl_signal(SIGINT, "signal_handler"); 
... 

現在,它的工作原理:

$ php testsignal.php 
Signal dispatched 
Running an infinite loop 
2012-10-08T09:57:51+02:00 
2012-10-08T09:57:52+02:00 
^CCaught a signal 2 
cleaning up 
2012-10-08T09:57:52+02:00 
2012-10-08T09:57:53+02:00 
^\Quit 
4

瞭解這一點很重要的是如何declare作品:http://www.php.net/manual/en/control-structures.declare.php

它或者n讓它包裝它在'根'腳本(index.php或類似的東西)中聲明的影響。

有趣的事實;中頻檢查各地declare(ticks = 1);不要緊,如果你刪除那些3行腳本將停止工作,如果你改變了檢查if (false)它會工作,申報似乎正常碼流的xD之外進行評估

+0

這是正確的,我即將發佈相同的更正。 – scipilot

0

Ruben de Vries糾正編譯時使用declare ticks後,原始代碼有兩個錯誤(除了缺少INT信號)。

正如魯本說:

if(false) declare(ticks=1); 

這是否宣告蜱進行處理。嘗試一下! 文檔繼續說你如何不能使用變量等。這是一個編譯時間的黑客。

而且使用的是pcntl_signal_dispatch()一個直接替代聲明蜱 - 它必須在代碼執行過程被稱爲 - 像蜱自動完成。所以在這樣的腳本頭部調用一次只會處理當時的任何信號

爲了使pcntl_signal_dispatch()像使用蜱驅動它一樣操作,您需要將它遍佈在您的代碼中......具體取決於您希望中斷何時生效。

至少:在初始啓動過程中收到

while(true){ 
    sleep(1); 
    echo date(DATE_ATOM). "\n"; 
    pcntl_signal_dispatch(); 
} 

所以原來的代碼實際上是用刻度爲PHP的所有版本,並另外檢查只是一個信號,如果版本低於5.3更大。不是OP的意圖。

就我個人而言,我發現使用蜱驅動PCNTL信號是一個巨大的麻煩。在我的情況下,「循環」是在第三方代碼,所以我不能添加調度方法,它的頂層申報蜱不生產生產,除非我將它添加到每個文件(一些自動加載,範圍或PHP7版本特定的問題,我認爲)。