PHP共享内存使用与信号控制实例分析

本文实例讲述了PHP共享内存使用与信号控制。分享给大家供大家参考,具体如下:

共享内存

共享内存的使用主要是为了能够在同一台机器不同的进程中共享一些数据,比如在多个 php-fpm 进程中共享当前进程的使用情况。这种通信也称为进程间通信(Inter-Process Communication),简称 IPC。

PHP 内置的 shmop 扩展 (Shared Memory Operations) 提供了一系列共享内存操作的函数(可能是用的人不多吧,这一块儿的文档还没有中文翻译)。在 Linux 上,这些函数直接是通过调用 shm* 系列的函数实现,而 Winodows 上也通过对系统函数的封装实现了同样的调用。

主要函数:

shmop_close — 关闭共享内存块

shmop_delete — 删除共享内存块

shmop_open — 创建或打开共享内存块

shmop_read — 从共享内存块中读取数据

shmop_size — 获取共享内存块的大小

shmop_write — 向共享内存块中写入数据

与此相关的还有一个很重要的函数:ftok,通过文件的 inode 信息(*nix 上通过 stat 或 ls -i 命令查看)创建 IPC 的唯一 key(文件/文件夹的 inode 是唯一的)。这个函数在 Linux 上也是直接调用同名的系统函数实现,Windows 上还是使用一些封装。

一个简单的计数例子:

<?php
# 创建一块共享内存
$shm_key = ftok(__FILE__, 't');
$shm_id = shmop_open($shm_key, 'c', 0644, 8);
# 读取并写入数据
$count = (int) shmop_read($shm_id, 0, 8) + 1;
shmop_write($shm_id, str_pad($count, 8, '0', STR_PAD_LEFT), 0);
// echo shmop_read($shm_id, 0, 8);
# 关闭内存块,并不会删除共享内存,只是清除 PHP 的资源
shmop_close($shm_id);

以上这段代码没执行一次计数加 1,而且数据是在不同进程之间共享的。也就是说除非手动删除这块内存使用,否则这个数据是不会重置的。

有个需要稍微注意的点:shmop_open 的第二个参数是个 flag,类似 fopen 的第二个参数,其取值有以前几个:

"a" 只读访问;

"c" 如果内存片段不存在,则创建,如果存在,则可读写;

"w" 读写;

"n" 创建新的内存片段,如果同样 key 的已存在,则会创建失败,这是为了安全使用共享内存考虑。

此外,由于使用的共享内存片段是固定长度的,在存储和读取的时候要计算好数据的长度,不然可能会写入失败或者读取空值。

信号控制

既然上面使用到了共享内存存储数据,就需要考虑是否有多个进程同时写入数据到共享内存的情况,是否需要避免冲突。如果是这样,就需要引入信号量进行控制。

PHP 也提供了类似的内置扩展 sysvsem(这个扩展在 Windows 环境下没有,文档中将 ftok 函数也归到这个扩展中,但实际上ftok 是在标准函数库中提供的,所以在 Windows 下也是可用的)。

在说信号量控制之前,先说另外一件有意思的事情:看官方文档你会发现这里同样也有共享内存操作的函数(shm_*),因为这其实是同一类别(或者说来自于同一作者)的三个扩展,还有一个是 sysvmsg(队列消息) 。函数的实现上稍有差别,但实际做的事情基本相同。这和上文的 shmop 扩展有什么区别呢?shmop 源码下的 README 文件有简单的说明:

PHP already had a shared memory extension (sysvshm) written by Christian Cartus <cartus@atrior.de>, unfortunately this extension was designed with PHP only in mind and offers high level features which are extremely bothersome for basic SHM we had in mind.

简单说来:sysvshm 扩展提供的方法并不是原封不动的存储用户的数据,而是先使用 PHP 的变量序列化函数对参数进行序列化然后再进行存储。这就导致通过这些方法存储的数据无法和非 PHP 进程共享。不过这样也能存储更丰富的 PHP 数据类型,上文的扩展中 shmop_write 只能写入字符串。那么为什么 sysvshm 同样不支持 Windows 呢?因为其并没有引入封装了 shm* 系列函数的tsrm_win32.h 的头文件。

引入信号控制之后的示例:

<?php
$id_key = ftok(__FILE__, 't');
$sem_id = sem_get($id_key);
# 请求信号控制权
if (sem_acquire($sem_id)) {
  $shm_id = shmop_open($id_key, 'c', 0644, 8);
  # 读取并写入数据
  $count = (int) shmop_read($shm_id, 0, 8) + 1;
  shmop_write($shm_id, str_pad($count, 8, '0', STR_PAD_LEFT), 0);
  // echo shmop_read($shm_id, 0, 8);
  # 关闭内存块
  shmop_close($shm_id);
  # 释放信号
  sem_release($sem_id);
}

但是本地想模拟实现写入冲突实际上是非常难的(考虑到计算机的执行速度)。在本地测试中,使用 for 循环操作时如果不使用shmop_close 关闭资源会出现无法打开共享内存的错误警告。这应该是因为正在共享内存被上一次操作占用中还没有释放导致。

更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP基本语法入门教程》、《PHP错误与异常处理方法总结》、《php程序设计算法总结》及《php面向对象程序设计入门教程》

希望本文所述对大家PHP程序设计有所帮助。

您可能感兴趣的文章:

  • 单台服务器的PHP进程之间实现共享内存的方法
  • PHP共享内存用法实例分析
  • php共享内存段示例分享
  • PHP进程通信基础之信号量与共享内存通信
  • PHP进程通信基础之信号
  • PHP 信号管理知识整理汇总
  • PHP信号量基本用法实例详解
  • PHP下通过系统信号量加锁方式获取递增序列ID
(0)

相关推荐

  • PHP进程通信基础之信号量与共享内存通信

    由于进程之间谁先执行并不确定,这取决于内核的进程调度算法,其中比较复杂.由此有可能多进程在相同的时间内同时访问共享内存,从而造成不可预料的错误.信号量这个名字起的令人莫名其妙,但是看其英文原意,就十分容易理解. semaphore 英[ˈseməfɔ:(r)] vt. 发出信号,打旗语; 类似于指挥官的作用. 下面我们看下一个伪代码信号量的使用. 1.创建信号量唯一标识符 $ftok = ftok(__FILE__, 'a'); 2.创建信号量资源ID $sem_resouce_id = sem

  • php共享内存段示例分享

    需要安装扩展shmop找到php安装源文件目录 复制代码 代码如下: # cd /usr/local/php-5.4.0/ext/shmop# /usr/local/php/bin/phpize# ./configure --with-php-config=/usr/local/php/bin/php-config#  make && make install 编译安装成功 复制代码 代码如下: # cd /usr/local/php/lib/php/extensions/no-debug

  • PHP共享内存用法实例分析

    本文实例讲述了PHP共享内存用法.分享给大家供大家参考,具体如下: 共享内存主要用于进程间通信 php中的共享内存有两套扩展可以实现 1.shmop  编译时需要开启 --enable-shmop 参数 实例: $shm_key = ftok(__FILE__, 't'); /** 开辟一块共享内存 int $key , string $flags , int $mode , int $size $flags: a:访问只读内存段 c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写

  • PHP下通过系统信号量加锁方式获取递增序列ID

    在网上搜了搜,有两个办法但都不太好:一个是简单的以进程ID+时间戳,或进程ID+随机数来产生近似的唯一ID,虽简单但对于追求"完美"的我不愿这样凑合,再说Apache2以后进程会维持相当长得时间,生成的ID发生碰撞的几率还是比较大的:第二个思路是通过Mysql的自增字段,这个就更不能考虑了,效率低不说,我的设计里压根就没数据库. 递增ID的获取是个过程: 1. 从全局某个存储中读取ID 2. 给ID加1 3. 将ID重新存入全局存储 在多进程或线程的程序中需要将上述3步作为单步的原子操

  • PHP进程通信基础之信号

    使用信号通信.可以使用kill -l 来查看当前系统的信号类型. 每个信号所代表的的详细含义,请查看我的这篇文章:http://www.jb51.net/article/106040.htm 使用信号的时候可以通过php --version 来查看当前PHP的版本.已决定使用哪种方式来进行进程间的信号通信. [root@roverliang ipc]# php --version PHP 5.6.24 (cli) (built: Aug 15 2016 19:14:02) Copyright (

  • 单台服务器的PHP进程之间实现共享内存的方法

    开发人员要想使php进程实现共享内存的读写,首先就要支持IPC函数,即php编译安装时指定:--enable-shmop  与--enable-sysvsem 两个选项. IPC (Inter-process communication) 是一个Unix标准机制,它提供了使得在同一台主机不同进程之间可以互相的方法.基本的IPC处理机制有3种:它们分别是共享内存.信号量和消息队列.本文中我们主要讨论共享内存和信号量的使用. 在不同的处理进程之间使用共享内存是一个实现不同进程之间相互的好方法.如果你

  • PHP 信号管理知识整理汇总

    SIGQUIT    建立CORE文件终止进程,并且生成core文件 SIGILL     建立CORE文件       非法指令 SIGTRAP    建立CORE文件       跟踪自陷 SIGBUS     建立CORE文件       总线错误 SIGSEGV    建立CORE文件        段非法错误 SIGFPE     建立CORE文件       浮点异常 SIGIOT     建立CORE文件        执行I/O自陷 SIGSTOP    停止进程     非终端

  • PHP信号量基本用法实例详解

    本文实例讲述了PHP信号量基本用法.分享给大家供大家参考,具体如下: 一些理论基础: 信号量:又称为信号灯.旗语 用来解决进程(线程同步的问题),类似于一把锁,访问前获取锁(获取不到则等待),访问后释放锁. 临界资源:每次仅允许一个进程访问的资源. 临界区:每个进程中访问临界资源的那段代码叫临界区 进程互斥:两个或以上的进程不能同时进入关于同一组共享变量的临界区域,即一个进程正在访问临界资源,另一个进程要想访问必须等待. 进程同步主要研究如何确定数个进程之间的执行顺序和避免数据竞争的问题 即,如

  • PHP共享内存使用与信号控制实例分析

    本文实例讲述了PHP共享内存使用与信号控制.分享给大家供大家参考,具体如下: 共享内存 共享内存的使用主要是为了能够在同一台机器不同的进程中共享一些数据,比如在多个 php-fpm 进程中共享当前进程的使用情况.这种通信也称为进程间通信(Inter-Process Communication),简称 IPC. PHP 内置的 shmop 扩展 (Shared Memory Operations) 提供了一系列共享内存操作的函数(可能是用的人不多吧,这一块儿的文档还没有中文翻译).在 Linux

  • PHP会话控制实例分析

    本文实例讲述了PHP会话控制.分享给大家供大家参考,具体如下: 关于cookie和session的测试代码: <?php session_start(); define('u','a'); define('p','1'); if (isset($_GET['r']) && $_GET['r']== 1) { unset($_COOKIE['username']); unset($_COOKIE['password']); unset($_SESSION['valid_login'])

  • Flask框架信号用法实例分析

    本文实例讲述了Flask框架信号用法.分享给大家供大家参考,具体如下: 项目功能复杂,代码量越大,就越需要做业务解耦.否则在其之上做开发和维护是很痛苦的,尤其是对于团队的新人.Flask从0.6开始,通过Blinker提供了信号支持.信号就是在框架核心功能或者一些Flask扩展发生工作时所发送的通知,用于帮助你解耦应用. Blinker的使用 安装 pip install blinker Blinker的信号与接收方式 from blinker import signal s = signal(

  • node 利用进程通信实现Cluster共享内存

    Node.js的标准API没有提供进程共享内存,然而通过IPC接口的send方法和对message事件的监听,就可以实现一个多进程之间的协同机制,通过通信来操作共享内存. ##IPC的基本用法: // worker进程 发送消息 process.send('读取共享内存'); // master进程 接收消息 -> 处理 -> 发送回信 cluster.on('online', function (worker) { // 有worker进程建立,即开始监听message事件 worker.o

  • nginx共享内存的机制详解

    目录 1 共享内存申请 2 共享内存实现原理 2.1 共享内存组织 2.2 slab共享内存管理机制 2.3 slab与ngx_shm_zone_t 关系 3 共享内存应用 1 共享内存申请 共享内存申请比较简单,这里采用的是Linux系统共享内存分配的函数实现的. #include <sys/ipc.h> #include <sys/shm.h> ngx_int_t ngx_shm_alloc(ngx_shm_t *shm) { int id; id = shmget(IPC_P

  • win32下进程间通信(共享内存)实例分析

    一.概述 很多情况下在Windows程序中,各个进程之间往往需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换. 进程间通讯(即:同机通讯)和数据交换有多种方式:消息.共享内存.匿名(命名)管道.邮槽.Windows套接字等多种技术."共享内存"(shared memory)可以定义为对一个以上的进程是可见的内存或存在于多个进程的虚拟地址空间.例如:如果两个进程使用相同的DLL,只把DLL的代码

  • Go语言共享内存读写实例分析

    本文实例分析了Go语言共享内存读写的方法.分享给大家供大家参考.具体分析如下: 前面分析了Go语言指针运算和内嵌C代码的方法,做了一个Go语言共享内存读写的实验. 先大概说下什么是共享内存.我们知道不同进程见的内存是互相独立的,没办法直接互相操作对方内的数据,而共享内存则是靠操作系统提供的内存映射机制,让不同进程的一块地址空间映射到同一个虚拟内存区域上,使不同的进程可以操作到一块共用的内存块.共享内存是效率最高的进程间通讯机制,因为数据不需要在内核和程序之间复制. 共享内存用到的是系统提供的mm

  • php进程(线程)通信基础之System V共享内存简单实例分析

    本文实例讲述了php进程(线程)通信基础之System V共享内存.分享给大家供大家参考,具体如下: PHP默认情况没有开启功能,要支持该功能在编译PHP的时候要加入下面几个选项  System V消息,--enable-sysvmsg   System V信号量支持,--enable-sysvsem  System V共享内存支持,--enable-sysvshm PHP还挺shmop共享内存,在编译的时候开启 --enable-shmop System V共享内存的相关函数: 1: 创建信号

  • Linux共享内存实现机制的详解

    Linux共享内存实现机制的详解 内存共享: 两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间.进程A可以即时看到进程B对共享内存中数据的更新,反之亦然.由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以. 效率: 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]: 一次从输入文件到

随机推荐