PHP Conference Japan 2024

pcntl_signal_dispatch

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

pcntl_signal_dispatch呼叫待處理訊號的訊號處理程式

說明

pcntl_signal_dispatch(): bool

pcntl_signal_dispatch() 函式會針對每個待處理的訊號呼叫由 pcntl_signal() 安裝的訊號處理程式。

參數

此函式沒有參數。

回傳值

成功時回傳 true,失敗時回傳 false

範例

範例 #1 pcntl_signal_dispatch() 範例

<?php
echo "安裝訊號處理器...\n";
pcntl_signal(SIGHUP, function($signo) {
echo
"訊號處理器被呼叫\n";
});

echo
"產生 SIGHUP 訊號給自己...\n";
posix_kill(posix_getpid(), SIGHUP);

echo
"分派...\n";
pcntl_signal_dispatch();

echo
"完成\n";

?>

上述範例會輸出類似以下的內容:

Installing signal handler...
Generating signal SIGHUP to self...
Dispatching...
signal handler called
Done

另請參閱

新增註釋

使用者貢獻的註釋 4 則註釋

webmaster at ajeux dot com
15 年前
如果您以 CLI 模式執行 PHP 並作為「守護行程」(例如在迴圈中),則必須在每個迴圈中呼叫此函式以檢查是否有新的訊號等待分派。
me at subsonic dot cz
10 年前
請注意,從先前 pcntl_signal_dispatch() 呼叫的訊號處理器內呼叫 pcntl_signal_dispatch() 不會觸發任何新的待處理訊號的處理器。這表示如果您編寫一個 CLI 守護行程,它會回應訊號而分支出子行程,那麼這些子行程將無法回應訊號。這讓我頭痛了一陣子,因為發生這種情況時,pcntl_signal_dispatch() 不會引發任何錯誤。一種解決方案是在訊號處理器內設定一個旗標,並在父行程主迴圈的其他地方對其做出反應(透過分支出所需的子行程)。
stefanis
10 年前
正如「me at subsonic dot net」所指出的,從先前 pcntl_signal_dispatch() 呼叫的訊號處理器內呼叫 pcntl_signal_dispatch() 不會觸發任何新的待處理訊號的處理器。即使您使用 pcntl_exec() 執行新的 PHP 處理器來執行完全不同的腳本,這似乎也是正確的。

解決方案似乎是在 ticks_handler() 內明確呼叫 pcntl_signal_dispatch()。並使用 sig_handler(int) 作為推播函式到佇列。在 ticks_handler 中呼叫 dispatch 之後,立即將佇列彈出,執行您在 signal_handler 中會執行的操作,直到佇列為空。
stefanis
10 年前
嗯,我之前說錯了。只在訊號處理函式外處理訊號是不夠的。它們必須在 tick 處理函式(顯式或隱式)之外處理。所以...

註冊一個呼叫 pcntl_signal_dispatch() 的 tick 處理函式;
在訊號處理函式中,將你的訊號加入佇列;
在你的腳本主迴圈中,處理你的訊號;

<?php
declare(ticks=1);
global
$sig_queue;
global
$use_queue;
$sig_queue = array();
$use_queue = true; // 設定為 false 以使用舊方法

function tick_handler()
{
pcntl_signal_dispatch();
}

function
sig_handler($sig)
{
global
$sig_queue;
global
$use_queue;

if(isset(
$use_queue) && $use_queue)
{
$sig_queue[] = $sig;
}
else
{
sig_helper($sig);
}
}

function
sig_helper($sig)
{
switch(
$sig)
{
case
SIGHUP:
$pid = pcntl_fork();
if(
$pid) print("forked $pid\n");
break;

default:
print(
"未處理的訊號: $sig\n");
}
}

pcntl_signal(SIGHUP, "sig_handler");

while(
true)
{
if(
$use_queue) foreach($sig_queue as $idx=>$sig)
{
sig_helper($sig);
unset(
$sig_queue[$idx]);
}
sleep(1);
}
?>
To Top