热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php进程间共享变量失败

背景:

背景:




想利用 PHP的shmop、ThinkPHP框架下的自定义命令行 实现一个常驻进程的自动任务,解决原本用crontab实现秒级别的麻烦,同时可以快速查看自动任务的状态,但要求确保当前的自动任务只起了一个进程。

问题:

在shmop创建一个共享内存,并存入值之后,在当前进程或其他进程都无法shmop_open?

代码:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

namespace app\autotask;



use think\console\Command;

use think\console\Input;

use think\console\Output;

use think\console\input\Argument;

use think\console\input\Option;

use think\Log;



class Demo extends Command

{

    const SHARE_SIZE = 1024;

    protected function configure()

    {

        //设置参数

        $this->addArgument('act', Argument::REQUIRED); //必传参数

        //帮助文档中的命令备注

        $this->setName('demo')->setDescription('Here is the remark of autotask-demo');

    }



    /**

     * 可以这样执行命令 php think demo start|stop|status

     * @param Input $input

     * @param Output $output

     */

    protected function execute(Input $input, Output $output)

    {

        //获取参数值

        $args = $input->getArguments();

        if(!in_array($args['act'],['start','stop','status'])){

            $output->writeln('Unknow args!');

        }

        switch ($args['act']){

            case 'start':

                $res = $this->setRuningStatus(true);

                if($res){

                    $msg ='Demo start success!';

                }else{

                    $msg ='Demo start fail!';

                }

                break;

            case 'stop':

                $res = $this->setRuningStatus(false);

                if($res){

                    $msg ='Demo stop success!';

                }else{

                    $msg ='Demo stop fail!';

                }

                break;

            case 'status':

                $population = $this->getRuningStatus();

                if($population===false){

                    $status = 'notfound';

                }elseif($population===1){

                    $status = 'start';

                }elseif($population===2){

                    $status = 'stop';

                }else{

                    $status = 'unknow';

                }

                $msg = "The Demo's status is ".$status;

                break;

        }

        $output->writeln($msg);

        if($args['act']=='start' && $res){

            $this->keepStart();

        }

    }



    protected function getRuningStatus()

    {

        $shmop_key = $this->getShmopKey();

        if($shmop_key==-1){

            return false;

        }

        $shmop_id = shmop_open($shmop_key,'w',0,self::SHARE_SIZE);

        $shmop_size = shmop_size($shmop_id);

        $population = shmop_read($shmop_id,0, $shmop_size);

        shmop_close($shmop_id);

        return $population;

    }



    protected function setRuningStatus($start)

    {

        $shmop_key = $this->getShmopKey();

        if($shmop_key==-1){

            return false;

        }

        $shmop_id = shmop_open($shmop_key,'c',0644,self::SHARE_SIZE);

        if($start===true){

            $population = 1;

        }else{

            $population = 2;

        }

        $shmop_bytes_written = shmop_write($shmop_id, $population,0);

        shmop_close($shmop_id);

        if ($shmop_bytes_written != strlen($population)) {

            return false;

        } else {

            return true;

        }

    }



    protected function getShmopKey()

    {

        if(!function_exists('ftok')) {

            $shmop_key = myftok(__FILE__, 23);

        }else{

            $shmop_key = ftok(__FILE__,'p');

        }

        return $shmop_key;

    }



    protected function keepStart()

    {

        $output = new Output;

        while (true){

            if($this->getRuningStatus()!==1) {

                $res = $this->setRuningStatus(true);

                if($res){

                    $msg ='Demo auto start success!';

                }else{

                    $msg ='Demo auto start fail!';

                }

                $output->writeln($msg);

            }else{

                sleep(3);

            }

        }

    }

}

1
2
3
4
5
6
7
8
9
10
//$shmop_key = ftok(__FILE__, 'p');  在win环境下,不支持这样的功能,故重写

function myftok($pathname, $proj_id)

{

    $st = @stat($pathname);

    if (!$st) {

        return -1;

    }

    $key = sprintf("%u", (($st['ino'] & 0xffff) | (($st['dev'] & 0xff) <<16) | (($proj_id & 0xff) <<24)));

    return $key;

}

报错信息:

shmop_open(): unable to attach to shared memory segment 'No error'

备注:

1.查找了很多资料,暂时没找到可解决的。
2.官方说shmop_open读取已有内存时,第3和第4个参数为0,但调试后发现这样会报另一个错误
shmop_open(): Shared memory segment size must be greater than zero
3.本人新手勿喷,请直戳重点,求大神解答,十分感谢!



   



推荐阅读
author-avatar
迷失港湾的豪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有