• php 共享内存


    共享内存主要用于进程间通信

     php中的共享内存有两套扩展可以实现

    1、shmop  编译时需要开启 --enable-shmop 参数

    实例:

      

    $shm_key = ftok(__FILE__, 't');
    
    /**
     开辟一块共享内存
     
    int $key , string $flags , int $mode , int $size 
    $flags: a:访问只读内存段
            c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写
            w:可读写的内存段
            n:创建一个新内存段,如果该内存段已存在,则会失败
    $mode: 八进制格式  0655
    $size: 开辟的数据大小 字节
    
     */
    
    $shm_id = shmop_open($shm_key, "c", 0644, 1024);
    
    /**
     * 写入数据 数据必须是字符串格式 , 最后一个指偏移量
     * 注意:偏移量必须在指定的范围之内,否则写入不了
     * 
     */
    $size = shmop_write($shm_id, 'songjiankang', 0);
    echo "write into {$size}";
    
    #读取的范围也必须在申请的内存范围之内,否则失败
    $data = shmop_read($shm_id, 0, 100);
    var_dump($data);
    
    #删除 只是做一个删除标志位,同时不在允许新的进程进程读取,当在没有任何进程读取时系统会自动删除
    shmop_delete($shm_id);
    
    #关闭该内存段
    shmop_close($shm_id);

    2、用 Semaphore 扩展中的 sem 类函数 (用起来更方便,类似 key-value 格式)

    // Get the file token key
    $key = ftok(__DIR__, 'a');
    
    // 创建一个共享内存
    $shm_id = shm_attach($key, 1024, 777); // resource type
    if ($shm_id === false) {
        die('Unable to create the shared memory segment');
    }
    
    #设置一个值
    shm_put_var($shm_id, 111, 'value');
    
    #删除一个key
    //shm_remove_var($shm_id, 111);
    
    #获取一个值
    $value = shm_get_var($shm_id,  111);
    var_dump($value);
    
    #检测一个key是否存在
    // var_dump(shm_has_var($shm_id,  111));
    
    #从系统中移除
    shm_remove($shm_id);
    
    #关闭和共享内存的连接
    shm_detach($shm_id);

     注意:这两种方式不通用的

     一个用共享内存和信号量实现的消息队列

    /**
    * 使用共享内存和信号量实现
    * 
    * 支持多进程, 支持各种数据类型的存储
    * 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区
    *
    */
    class ShmQueue
    {
    
        private $maxQSize = 0; // 队列最大长度
        private $front = 0; // 队头指针
        private $rear = 0; // 队尾指针
        private $blockSize = 256; // 块的大小(byte)
        private $memSize = 25600; // 最大共享内存(byte)
        private $shmId = 0;
    
        private $filePtr = './shmq.ptr';
    
        private $semId = 0;
    
        public function __construct ()
        {
            $shmkey = ftok(__FILE__, 't');
            
            $this->shmId = shmop_open($shmkey, "c", 0644, $this->memSize);
            $this->maxQSize = $this->memSize / $this->blockSize;
            
            // 申請一个信号量
            $this->semId = sem_get($shmkey, 1);
            sem_acquire($this->semId); // 申请进入临界区
            
            $this->init();
        }
    
        private function init ()
        {
            if (file_exists($this->filePtr)) {
                $contents = file_get_contents($this->filePtr);
                $data = explode('|', $contents);
                if (isset($data[0]) && isset($data[1])) {
                    $this->front = (int) $data[0];
                    $this->rear = (int) $data[1];
                }
            }
        }
    
        public function getLength ()
        {
            return (($this->rear - $this->front + $this->memSize) % ($this->memSize)) /
                     $this->blockSize;
        }
    
        public function enQueue ($value)
        {
            if ($this->ptrInc($this->rear) == $this->front) { // 队满
                return false;
            }
            
            $data = $this->encode($value);
            shmop_write($this->shmId, $data, $this->rear);
            $this->rear = $this->ptrInc($this->rear);
            return true;
        }
    
        public function deQueue ()
        {
            if ($this->front == $this->rear) { // 队空
                return false;
            }
            $value = shmop_read($this->shmId, $this->front, $this->blockSize - 1);
            $this->front = $this->ptrInc($this->front);
            return $this->decode($value);
        }
    
        private function ptrInc ($ptr)
        {
            return ($ptr + $this->blockSize) % ($this->memSize);
        }
    
        private function encode ($value)
        {
            $data = serialize($value) . "__eof";
            echo '';
            
            echo strlen($data);
            echo '';
            
            echo $this->blockSize - 1;
            echo '';
            
            if (strlen($data) > $this->blockSize - 1) {
                throw new Exception(strlen($data) . " is overload block size!");
            }
            return $data;
        }
    
        private function decode ($value)
        {
            $data = explode("__eof", $value);
            return unserialize($data[0]);
        }
    
        public function __destruct ()
        {
            $data = $this->front . '|' . $this->rear;
            file_put_contents($this->filePtr, $data);
            
            sem_release($this->semId); // 出临界区, 释放信号量
        }
    }
    
    /*
     * // 进队操作 $shmq = new ShmQueue(); $data = 'test data'; $shmq->enQueue($data);
     * unset($shmq); // 出队操作 $shmq = new ShmQueue(); $data = $shmq->deQueue();
     * unset($shmq);
     */

     linux下 用 ipc命令查看 ,用 ipcrm 命令可以删除

    参考:http://www.laruence.com/2008/04/21/101.html

        http://www.yuansir-web.com/2012/09/22/php

  • 相关阅读:
    理解C#中的 async await
    kube-proxy IPVS 模式的工作原理
    Kilo 使用教程
    Wireguard 全互联模式(full mesh)配置指南
    我为什么不鼓吹 WireGuard
    iTerm2 实现 ssh 自动登录,并使用 Zmodem 实现快速传输文件
    在 Docker Desktop 中启用 K8s 服务
    ABP 适用性改造
    ABP 适用性改造
    在 ASP.NET Core 应用中使用 Cookie 进行身份认证
  • 原文地址:https://www.cnblogs.com/siqi/p/3997444.html
Copyright © 2020-2023  润新知