workman源代码阅读 - 使用信号处理器实现定时器

时间:2022-01-20 09:05:29
<?php

/**
* SIGALRM信号处理器注册成功后,在什么情况下进程会收到该信号呢?
*
* 在Linux系统下,每个进程都有惟一的一个定时器,该定时器提供了以秒为单位的定时功能。在定时器设置的超时时间到达后,调用alarm的进程将收到SIGALRM信号。
*/ /**
* 启动信号处理器
*/
\MySignalClazz::init(); /**
* 信号处理器
* @author Administrator
*
*/
class MySignalClazz { /**
* Tasks that based on ALARM signal.
* [
* run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
* run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
* ..
* ]
*
* @var array
*/
protected static $_tasks = array(); /**
* 注册信号处理器
*/
public static function init()
{
pcntl_signal(SIGALRM, array('\MySignalClazz', 'signalHandle'), false);
} /**
* 信号处理器
* ALARM signal handler.
* @return void
*/
public static function signalHandle(){
pcntl_alarm(1); // 创建一个计时器,在1秒后向进程发送一个SIGALRM信号
self::tick();
} /**
* Add a timer.
*
* @param int $time_interval
* @param callback $func
* @param mixed $args
* @param bool $persistent
* @return bool
*/
public static function add($time_interval, $func, $args = array(), $persistent = true)
{
if ($time_interval <= 0) {
echo new Exception("bad time_interval");
return false;
} if (!is_callable($func)) {
echo new Exception("not callable");
return false;
} if (empty(self::$_tasks)) {
pcntl_alarm(1); // 重新启动定时器,实现1秒定时
} $time_now = time();
$run_time = $time_now + $time_interval; // 计算执行时间
if (!isset(self::$_tasks[$run_time])) {
self::$_tasks[$run_time] = array();
}
self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval);
return true;
} /**
* 单次执行函数
*/
public static function tick()
{
if (empty(self::$_tasks)) {
pcntl_alarm(0); // 不在创建新的信号
return;
} $time_now = time();
foreach (self::$_tasks as $run_time => $task_data) {
if ($time_now >= $run_time) { // 到达执行时间
foreach ($task_data as $index => $one_task) {
$task_func = $one_task[0];
$task_args = $one_task[1];
$persistent = $one_task[2];
$time_interval = $one_task[3];
try {
call_user_func_array($task_func, $task_args); // 执行注册的函数
} catch (\Exception $e) {
echo $e;
}
if ($persistent) {
self::add($time_interval, $task_func, $task_args); // 重新计算下次执行时间,添加进去
}
}
unset(self::$_tasks[$run_time]); // 执行完就删除掉
}
}
}
}