略微加速

PHP官方手册 - 互联网笔记

PHP - Manual: pcntl_alarm

2024-05-02

pcntl_alarm

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

pcntl_alarm为进程设置一个alarm闹钟信号

说明

pcntl_alarm(int $seconds): int

创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm()的调用都会取消之前设置的alarm信号。

参数

seconds

等待的秒数。如果seconds设置为0,将不会创建alarm信号。

返回值

返回上次alarm调度(离alarm信号发送)剩余的秒数,或者之前没有alarm调度(译注:或者之前调度已完成) 时返回0

add a noteadd a note

User Contributed Notes 3 notes

up
15
kuba at valentine dot dev
1 year ago
This is that universal timeout functionality you dreamed about and always wanted to have and guess what - it's as reliable as it gets, it's basically bulletproof. It can interrupt absolutely anything you throw at it and more, you name it - socket_connect(), socket_read(), fread(), infinite while() loops, sleep(), semaphores - seriously, any blocking operation. You can specify your own handler and just get over anything that normally would make your code unresponsive.

<?php
/**
* Because we shouldn't handle asynchronous
* events in synchronous manner.
*/
pcntl_async_signals(TRUE);

/**
* Some flag we can change to know for sure
* that our operation timed out.
*/
$timed_out = FALSE;

/**
* Register SIGALRM signal handler to avoid
* getting our process killed when signal arrives.
*/
pcntl_signal(SIGALRM, function($signal) use (&$timed_out) {
 
$timed_out = TRUE;
});

/**
* Now we set our timeout for 2 seconds, but it's not set in stone
* we can call pcntl_alarm() anytime to extend or to turn if off.
*/
pcntl_alarm(2);

/**
* Here we do something with unpredictable outcome that could
* possibly block our program for a very long time.
* I like sockets as an example, but it can be anything.
*/
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$connection = socket_connect($socket, 'irc.ircnet.com', 6667);

/**
* If our blocking operation didn't timed out then
* timer is still ticking, we should turn it off ASAP.
*/
$timed_out || pcntl_alarm(0);

/**
* And now we do whatever we want to do.
*/
$status = $connection ? 'Connected.' : ($timed_out ? 'Timed out.' : socket_strerror(socket_last_error($socket)));
echo
'STATUS: '. $status . PHP_EOL;
up
0
molsavsky1 at gmail dot com
6 months ago
Beware that pcntl_signal will interrupt (u)sleep calls which will not be resumed once the handler is completed.

It's a documented behaviour (https://www.php.net/manual/en/function.sleep.php) although it may look like a bug when encountered for the first time.

From the docs:
"If the call was interrupted by a signal, sleep() returns a non-zero value. On Windows, this value will always be 192 (the value of the WAIT_IO_COMPLETION constant within the Windows API). On other platforms, the return value will be the number of seconds left to sleep."

```
<?php

$interval
= 1;
pcntl_async_signals(true);

pcntl_signal(SIGALRM, function () use ($interval): void {
    echo
'SIGALRM called' . PHP_EOL;
   
pcntl_alarm($interval);
});

pcntl_alarm($interval);

echo
'Sleep (will be interrupted) started' . PHP_EOL;

sleep(100000000000);

echo
'Sleep ended soon due to interrupt' . PHP_EOL;

$sleepTimeout = 10;
echo
"Proper sleep for {$sleepTimeout} seconds" . PHP_EOL;

$startedAt = time();
while (
$sleepTimeout > 0 && ($sleepTimeout = sleep($sleepTimeout)) !== true) {
    echo
"Sleep interrupted, {$sleepTimeout} seconds remaining" . PHP_EOL;
}

$elapsed = time() - $startedAt;
echo
"Sleep finished after {$elapsed} seconds" . PHP_EOL;
```
up
-3
Gao,Shengwei
4 years ago
Use pcntl_signal_dispatch() to catch the signal, don't use declare(ticks=1) because it is ineffcient

<?php
pcntl_signal
(SIGALRM, function () {
    echo
'Received an alarm signal !' . PHP_EOL;
},
false);

pcntl_alarm(5);

while (
true) {
   
pcntl_signal_dispatch();
   
sleep(1);
}

官方地址:https://www.php.net/manual/en/function.pcntl-alarm.php

北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3