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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了workman源代码阅读 - 使用信号处理器实现定时器相关的知识,希望对你有一定的参考价值。

<?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]); // 执行完就删除掉
            }
        }
    }
}

 

以上是关于workman源代码阅读 - 使用信号处理器实现定时器的主要内容,如果未能解决你的问题,请参考以下文章

Windows下安装使用workman简单实例

Windows下安装使用workman简单实例

php如何实现websocket

websocket 后台新订单通知 —— Laravel 5.8 workman PHPSocket.IO教程

websocket 后台新订单通知 —— Laravel 5.8 workman PHPSocket.IO教程

ThinkPHP5中使用workman框架与硬件设备蓝牙锁通讯