原创文章,转载请注明出处:http://huyanping.sinaapp.com/?p=222

作者:Jenner

一、场景描写叙述:

近期我们一块业务。须要不断的监听一个文件夹的变化。假设文件夹中有文件,则启动PHP脚本处理掉。

最初的方案是使用crontab运行sh脚本,脚本大概例如以下:

SOK=`ps -ef |grep /www/sender.sh | grep -v grep|wc -l`
if [[ "$SOK" < "2" ]];then
for f in `ls /www/queue`; do
php /www/logsender.php /www/queue/$f
done

实际执行中出现了异常:ps -ef | grep xxx的方式,可能无法正确的推断进程是否正在执行。if条件永远都不会成立。使得PHP脚本永远不会执行。经过考虑后,决定建立一个独立于其它模块的,可以实现进程单例执行的类,解决问题。

 二、方案设计

1、通过PID文件实现进程单例

2、程序启动、退出自己主动创建、删除PID文件。做到不须要业务代码考虑PID文件删除

3、尽量保证代码独立性。不影响业务代码

三、原理

1、启动创建PID文件

2、绑定程序退出、被杀死等信号量,用于删除PID文件

3、加入析构函数。对象被销毁时,删除PID文件

四、遇到的问题

程序正常退出时。无法捕获到信号量,不知道是不是信号量选错了,ctrl+c等信号是正常的,假设能够解决捕获程序正常退出时的信号量。则能够替代析构函数方案,更加稳定

五、代码



<?php
/**
* Created by PhpStorm.
* User: huyanping
* Date: 14-8-13
* Time: 下午2:25
*
* 实现程序单例执行。调用方式:
* declare(ticks = 1);//注意:一定要在外部调用文件里首部调用该声明,否则程序会无法监听到信号量
* $single = new DaemonSingle(__FILE__);
* $single->single();
*
*/ class DaemonSingle { //PID文件路径
private $pid_dir; //PID文件名
private $filename; //PID文件完整路径名称
private $pid_file; /**
* 构造函数
* @param $filename
* @param string $pid_dir
*/
public function __construct($filename, $pid_dir='/tmp/'){
if(empty($filename)) throw new JetException('filename cannot be empty...');
$this->filename = $filename;
$this->pid_dir = $pid_dir;
$this->pid_file = $this->pid_dir . DIRECTORY_SEPARATOR . substr(basename($this->filename), 0, -4) . '.pid';
} /**
* 单例模式启动接口
* @throws JetException
*/
public function single(){
$this->check_pcntl();
if(file_exists($this->pid_file)) {
throw new Exception('the process is already running...');
}
$this->create_pid_file();
} /**
* @throws JetException
*/
private function create_pid_file()
{
if (!is_dir($this->pid_dir)) {
mkdir($this->pid_dir);
}
$fp = fopen($this->pid_file, 'w');
if(!$fp){
throw new Exception('cannot create pid file...');
}
fwrite($fp, posix_getpid());
fclose($fp);
$this->pid_create = true;
} /**
* 环境检查
* @throws Exception
*/
public function check_pcntl()
{
// Make sure PHP has support for pcntl
if (!function_exists('pcntl_signal')) {
$message = 'PHP does not appear to be compiled with the PCNTL extension. This is neccesary for daemonization';
throw new Exception($message);
}
//信号处理
pcntl_signal(SIGTERM, array(&$this, "signal_handler"));
pcntl_signal(SIGINT, array(&$this, "signal_handler"));
pcntl_signal(SIGQUIT, array(&$this, "signal_handler")); // Enable PHP 5.3 garbage collection
if (function_exists('gc_enable')) {
gc_enable();
$this->gc_enabled = gc_enabled();
}
} /**
* 信号处理函数,程序异常退出时。安全删除PID文件
* @param $signal
*/
public function signal_handler($signal)
{
switch ($signal) {
case SIGINT :
case SIGQUIT:
case SIGTERM:{
self::safe_quit();
break;
}
}
} /**
* 安全退出,删除PID文件
*/
public function safe_quit()
{
if (file_exists($this->pid_file)) {
$pid = intval(posix_getpid());
$file_pid = intval(file_get_contents($this->pid_file));
if($pid == $file_pid){
unlink($this->pid_file);
}
}
posix_kill(0, SIGKILL);
exit(0);
} /**
* 析构函数,删除PID文件
*/
public function __destruct(){
$this->safe_quit();
}
}

PHP实现程序单例执行的更多相关文章

  1. C#实现程序单例日志输出

    对于一个完整的程序系统,一个日志记录是必不可少的.可以用它来记录程序在运行过程中的运行状态和报错信息.比如,那些不想通过弹框提示的错误,程序执行过程中捕获的异常等. 首先,在你的解决方案中,适当的目录 ...

  2. C#应用程序单例并激活程序的窗口 使其显示在最前端

    public class SoftHelper { ///<summary> /// 该函数设置由不同线程产生的窗口的显示状态 /// </summary> /// <p ...

  3. Inno Setup安装程序单例运行

    1.源起: KV项目下载底层升级包,老是报出升级文件占用问题,反复分析,不得其所. 今天突然发现同时启动多个升级程序实例,分析认为安装包同时被调用多次,引发实例访问文件冲突,导致此问题. 安装程序由I ...

  4. C# 应用程序单例(禁止多开) 获取.net版本号 以及 管理员权限

    Mutex不仅提供跨线程的服务,还提供跨进程的服务.当在构造函数中为Mutex指定名称时,则会创建一个命名了的Mutex.其他线程创建Mutex时,如果指定的名称相同,则返回同一个互斥体,不论该线程位 ...

  5. 编写一个Singleton程序(单例)

    public class Test { private static Test test = new Test(); private Test(){}//构造方法私有化 private static ...

  6. 23种设计模式之单例(Singleton Pattern)

    单例 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例(eg:应对一些特殊情况,比如数据库连接池(内置了资源)  全局唯一号码生成器),才能确保它们的逻辑正确性.以及良好的效率 ...

  7. shell单例-处理方案

    shell单例:当某一个shell脚本需要重复执行时(shell定时任务 etc),为了避免多个相同任务之间交叉,造成数据的混乱或者错误,需要脚本单例执行. 就是前一个进程执行时,后一个进程需要阻塞等 ...

  8. JAVASE(十七) 多线程:程序、进程、线程与线程的生命周期、死锁、单例、同步锁

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1.程序.进程.线程的理解 1.1 概念 程序(program)是为完成特定任务.用某种语言编写的一组指 ...

  9. QT中实现应用程序的单例化

    一介绍 通过编写一个QSingleApplication类,来实现Qt程序的单例化,原文的作者是在Windows Vista + Qt4.4 下实现的,不过应用在其他平台上是没问题的.(本文是我在ht ...

随机推荐

  1. Java实现POI读取Excel文件,兼容后缀名xls和xlsx

    1.引入所需的jar包: maven管理项目的话直接添加以下坐标即可: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -- ...

  2. react native android 应用状态(前端或后台)的判断

    当Android应用程序被暂时放到了后台,或者又重新回到前台,是否有相应的事件可以处理到? 例如,当你的应用暂时放到了后台,是否应该做出一些操作,暂时保存界面上的数据? 可以参考:https://gi ...

  3. Python 2.7.13安装

    参考文章:安装Python 进入至Python官方网站,点击下载 下载完成后直接进行安装 选择安装的路径 选择安装的组件,请注意选择安装pip和Add python.exe to Path这两个选项 ...

  4. Excel Application对象应用

    Application对象是Excel对象模型中最高层级的对象,代表Excel应用程序自身,也包含组成工作簿的许多部分,包括工作簿.工作表.单元格集合以及它们包含的数据. Application对象包 ...

  5. POJ1958 Strange Towers of Hanoi [递推]

    题目传送门 Strange Towers of Hanoi Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3117   Ac ...

  6. Linux用户密码文件/etc/shadow相关

    (1).密码文件 [root@xuexi ~]# head -3 /etc/shadow root:$6$kcgcu794R0VP3fDL$aYN8XUbtWvZ4QQtT2xVW.N2CgE3YLP ...

  7. Server SQL 2008 练习

    一.修改数据库 (1)给db_temp数据库添加一个数据文件文件db_temp1指定大小为5MB,最大文件大小为100mb,自动递增大小为1MB,存储路径为d:\. 利用系统存储过程sp_helpdb ...

  8. hdu 2196(Computer 树形dp)

    A school bought the first computer some time ago(so this computer's id is 1). During the recent year ...

  9. 【BZOJ 4025】 (CDQ?还是整体二分?+并查集及它的恢复操作)

    4025: 二分图 Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考 ...

  10. OPENCV下SIFT算法使用方法笔记

    这几天继续在看Lowe大神的SIFT神作,看的眼花手脚抽筋.也是醉了!!!!实在看不下去,来点干货.我们知道opencv下自带SIFT特征检测以及MATCH匹配的库,这些库完全可以让我们进行傻瓜似的操 ...