pcntl_alarm

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

pcntl_alarmSetzt einen Zeitschalter für die Auslieferung eines Signals

Beschreibung

pcntl_alarm(int $seconds): int

Erzeugt eine Zeitschaltuhr, die ein SIGALRM Signal an den Prozess senden wird, nachdem die angegebene Anzahl von Sekunden vergangen sind. Jeder Aufruf von pcntl_alarm() wird jeden zuvor erzeugten Zeitschalter abbrechen.

Parameter-Liste

seconds

Die zu wartende Anzahl von Sekunden. Ist seconds 0, wird kein neuer Zeitschalter erzeugt.

Rückgabewerte

Gibt die Zeitangabe in Sekunden zurück, die ein zuvor angesetzter Zeitschalter übrig hatte, bevor er ausgeliefert werden sollte, oder 0, wenn es keinen vorher angesetzten Zeitschalter gab.

add a note

User Contributed Notes 3 notes

up
22
kuba at valentine dot dev
2 years 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
1
molsavsky1 at gmail dot com
11 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);
}
To Top