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 相关文章推荐
用PHP实现多服务器共享SESSION数据的方法
Mar 16 PHP
php调用Google translate_tts api实现代码
Aug 07 PHP
9段PHP实用功能的代码推荐
Oct 14 PHP
PHP清除数组中所有字符串两端空格的方法
Oct 20 PHP
php中的字符编码转换函数用法示例
Oct 20 PHP
php实现的简单日志写入函数
Mar 31 PHP
php将字符串随机分割成不同长度数组的方法
Jun 01 PHP
PHP使用内置函数file_put_contents写入文件及追加内容的方法
Dec 07 PHP
PHP安装GeoIP扩展根据IP获取地理位置及计算距离的方法
Jul 01 PHP
Yii Framework框架使用PHPExcel组件的方法示例
Jul 24 PHP
PHP实现批量修改文件名的方法示例
Sep 18 PHP
实例化php类时传参的方法分析
Jun 05 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
攻克CakePHP系列二 表单数据显示
2008/10/22 PHP
php+xml编程之SimpleXML的应用实例
2015/01/24 PHP
Aster vs KG BO3 第一场2.19
2021/03/10 DOTA
javascript 嵌套的函数(作用域链)
2010/03/15 Javascript
根据json字符串生成Html的一种方式
2013/01/09 Javascript
javascript中数组和字符串的方法对比
2016/07/20 Javascript
js阻止冒泡和默认事件(默认行为)详解
2016/10/20 Javascript
nodejs redis 发布订阅机制封装实现方法及实例代码
2016/12/15 NodeJs
JS实现的四级密码强度检测功能示例
2017/05/11 Javascript
jQuery实现下拉菜单的实例代码
2017/06/19 jQuery
使用async、enterproxy控制并发数量的方法详解
2018/01/02 Javascript
nodejs结合Socket.IO实现的即时通讯功能详解
2018/01/12 NodeJs
详解从买域名到使用pm2部署node.js项目全过程
2018/03/07 Javascript
Angularjs实现多图片上传预览功能
2018/07/18 Javascript
JavaScript创建对象的常用方式总结
2018/08/10 Javascript
vue设置动态请求地址的例子
2019/11/01 Javascript
node.js使用 http-proxy 创建代理服务器操作示例
2020/02/10 Javascript
[01:42]TI4西雅图DOTA2前线报道 第一顿早饭哦
2014/07/08 DOTA
[01:11:11]Alliance vs RNG 2019国际邀请赛淘汰赛 败者组BO1 8.20.mp4
2020/07/19 DOTA
Python实现的监测服务器硬盘使用率脚本分享
2014/11/07 Python
Python实现选择排序
2017/06/04 Python
Python实现的桶排序算法示例
2017/11/29 Python
Caffe均值文件mean.binaryproto转mean.npy的方法
2018/07/09 Python
python 遗传算法求函数极值的实现代码
2020/02/11 Python
python新手学习使用库
2020/06/11 Python
植物选择:Botanic Choice
2017/02/15 全球购物
多媒体编辑专业毕业生推荐信
2013/11/05 职场文书
表彰大会主持词
2014/03/26 职场文书
初中学校军训方案
2014/05/09 职场文书
音乐教师求职信
2014/06/28 职场文书
党校毕业心得体会
2014/09/13 职场文书
城管执法人员纪律作风整顿思想汇报
2014/09/13 职场文书
解决MySQL存储时间出现不一致的问题
2021/04/28 MySQL
浅谈Python数学建模之整数规划
2021/06/23 Python
Pandas实现DataFrame的简单运算、统计与排序
2022/03/31 Python
JS实现简单的九宫格抽奖
2022/06/28 Javascript