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


Posted in PHP onMay 09, 2018

本文实例讲述了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 相关文章推荐
dedecms系统常用术语汇总
Apr 03 PHP
linux php mysql数据库备份实现代码
Mar 10 PHP
PHP字符串 ==比较运算符的副作用
Oct 21 PHP
PHP 函数执行效率的小比较
Oct 17 PHP
php中根据某年第几天计算出日期年月日的代码
Feb 24 PHP
php目录拷贝实现方法
Jul 10 PHP
php代码检查代理ip的有效性
Aug 19 PHP
php mysql_real_escape_string addslashes及mysql绑定参数防SQL注入攻击
Dec 23 PHP
php动态读取数据清除最右边距的方法
Apr 12 PHP
PHP获取redis里不存在的6位随机数应用示例【设置24小时过时】
Jun 07 PHP
Laravel5.0+框架邮件发送功能实现方法图文与实例详解
Apr 23 PHP
Vagrant(WSL)+PHPStorm+Xdebu 断点调试环境搭建
Dec 13 PHP
php curl批处理实现可控并发异步操作示例
May 09 #PHP
php使用curl伪造来源ip和refer的方法示例
May 08 #PHP
PHP+ajax实现获取新闻数据简单示例
May 08 #PHP
PHP 计算两个特别大的整数实例代码
May 07 #PHP
详解PHP发送邮件知识点
May 06 #PHP
PHP学习笔记之session
May 06 #PHP
PHP中cookie知识点学习
May 06 #PHP
You might like
php实现用于计算执行时间的类实例
2015/04/18 PHP
Hutia 的 JS 代码集
2006/10/24 Javascript
JavaScript之appendChild、insertBefore和insertAfter使用说明
2010/12/30 Javascript
javascript string字符串优化问题
2011/07/31 Javascript
JavaScript高级程序设计 读书笔记之十一 内置对象Global
2012/03/07 Javascript
javascript jscroll模拟html元素滚动条
2012/12/18 Javascript
JS获取当前网址、主机地址项目根路径
2013/11/19 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
nodejs微信公众号支付开发
2016/09/19 NodeJs
BootStrap实现鼠标悬停下拉列表功能
2017/02/17 Javascript
Angular2 Service实现简单音乐播放器服务
2017/02/24 Javascript
jQuery中的deferred使用方法
2017/03/27 jQuery
jQuery回调方法使用示例
2017/06/26 jQuery
ES6 Object方法扩展的应用实例分析
2019/06/25 Javascript
vue配置nprogress实现页面顶部进度条
2019/09/21 Javascript
Vue常用传值方式、父传子、子传父及非父子实例分析
2020/02/24 Javascript
js定时器出现第一次延迟的原因及解决方法
2021/01/04 Javascript
Python中函数参数设置及使用的学习笔记
2016/05/03 Python
如何在Python函数执行前后增加额外的行为
2016/10/20 Python
Python爬虫实例扒取2345天气预报
2018/03/04 Python
python实现人脸识别经典算法(一) 特征脸法
2018/03/13 Python
python 除法保留两位小数点的方法
2018/07/16 Python
Python OpenCV实现鼠标画框效果
2020/08/19 Python
python3实现高效的端口扫描
2019/08/31 Python
Python利用全连接神经网络求解MNIST问题详解
2020/01/14 Python
Html5调用手机摄像头并实现人脸识别的实现
2018/12/21 HTML / CSS
ASOS英国官网:英国在线时装和化妆品零售商
2017/05/19 全球购物
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
EntityManager都有哪些方法
2013/11/01 面试题
工地资料员岗位职责
2013/12/31 职场文书
2014优秀大学生简历自我评价
2014/09/15 职场文书
2014年社区重阳节活动策划方案
2014/09/16 职场文书
党员三严三实心得体会
2014/10/13 职场文书
保卫工作个人总结
2015/03/03 职场文书
辞职报告(范文三篇)
2019/08/27 职场文书
感恩信:写给爸爸妈妈的一封感谢信
2019/09/12 职场文书