PHP中实现进程间通讯


Posted in PHP onOctober 09, 2006

PHP中实现进程间通讯

邱文宇  

本文将讨论在PHP4环境下如何使用进程间通讯机制——IPC(Inter-Process-Communication)。本文讨论的软件环境是linux+php4.0.4或更高版本。首先,我们假设你已经装好了PHP4和UNIX, 为了使得php4可以使用共享内存和信号量,必须在编译php4程序时激活shmop和sysvsem这两个扩展模块。
实现方法:在PHP设定(configure)时加入如下选项。
--enable-shmop --enable-sysvsem  
这样就使得你的PHP系统可以处理相关的IPC函数了。
IPC是什么?
IPC (Inter-process communication) 是一个Unix标准通讯机制,它提供了使得在同一台主机不同进程之间可以互相通讯的方法。基本的IPC处理机制有3种:它们分别是共享内存、信号量和消息队列。本文中我们主要讨论共享内存和信号量的使用。关于消息队列,笔者在不久的将来还会专门介绍。
在PHP中使用共享内存段
在不同的处理进程之间使用共享内存是一个实现不同进程之间相互通讯的好方法。如果你在一个进程中向所共享的内存写入一段信息,那么所有其他的进程也可以看到这段被写入的数据。非常方便。在PHP中有了共享内存的帮助,你可以实现不同进程在运行同一段PHP脚本时返回不同的结果。或实现对PHP同时运行数量的实时查询等等。
共享内存允许两个或者多个进程共享一给定的存储区。因为数据不需要在客户机和服务器之间复制,所以这是最快的一种IPC。使用共享内存的唯一窍门是多个进程对一给定存储区的同步存取。
如何建立一个共享内存段呢?下面的代码可以帮你建立共享内存。
$shm_id = shmop_open($key, $mode, $perm, $size);
注意,每个共享内存段都有一个唯一的ID, 在PHP中,shmop_open会把建立好的共享内存段的ID返回,这里我们用$shm_id记录它。而$key是一个我们逻辑上表示共享内存段的Key值。不同进程只要选择同一个Key id就可以共享同一段存储段。习惯上我们用一个串(类似文件名一样的东西)的散列值作为key id. $mode指明了共享内存段的使用方式。这里由于是新建,因此值为'c' ?取create之意。如果你是访问已经建立过的共享内存那么请用'a',-- 取access之意。$perm参数定义了访问的权限,8进制,关于权限定义请看UNIX文件系统帮助。$size定义了共享内存的大小。尽管有点象fopen(文件处理)你可不要当它同文件处理一样。后面的描述你将看到着一点。
例如:
$shm_id = shmop_open(0xff3, "c", 0644, 100);
这里我们打开了一个共享内存段 键值0xff3 ?rw-r—r—格式,大小为100字节。
如果需要访问已有的共享内存段,你必须在调用shmop_open中设第3、4个参数为0。
IPC工作状态的查询
在Unix下,你可以用一个命令行程序ipcs查询系统所有的IPC资源状态。不过有些系统要求需要超级用户方能执行。下图是一段ipcs的运行结果。  

上图中系统显示了4个共享内存段,注意其中第4个键值为0x00000ff3的就是我们刚刚运行过的PHP程序所创建的。关于ipcs的用法请参考UNIX用户手册。
如何释放共享内存呢
释放共享内存的办法是调用PHP指令:shmop_delete($id)
shmop_delete($id);
$id 就是你调用shmop_open所存的shmop_op的返回值。还有一个办法就是用UNIX的管理指令:
ipcrm id, id就是你用ipcs看到的ID.和你程序中的$id不一样。不过要小心,如果你用ipcrm直接删除共享内存段那么有可能导致其他不知道这一情况的进程在引用这个已经不复存在的共享内存器时出现一些不可预测的错误(往往结果不妙)。
如何使用(读写)共享内存呢
使用如下所示函数向共享内存写入数据
int shmop_write (int shmid, string data, int offset)
其中shmid是用shmop_open返回的句柄。$Data变量存放了要存放的数据。$offset描述了写入从共享内存的开始第一个字节的位置(以0开始)。
读取操作是:
string shmop_read (int shmid, int start, int count)
同样,指明$shmid,开始偏移量(以0开始)、总读取数量。返回结果串。这样,你就可以把共享内存段当作是一个字节数组。读几个再写几个,想干嘛就干嘛,十分方便。
多进程问题的考虑
现在,在单独的一?玫揭桓龃砦蟮氖?荩?蛭?枚文诖娼??赡苁亲詈笾葱械慕?痰哪谌荩?踔潦怯?个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。为了解决这个问题,我们必须引入互斥机制。互斥机制在很多操作系统的教材上都有专门讲述,这里不多重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另外一种进程间通讯(IPC)的方式,它同其他IPC机构(管道、FIFO、消息队列)不同。它是一个记数器,用于控制多进程对共享数据的存储。同样的是你可以用ipcs和ipcrm实现对信号灯使用状态的查询和对其实现删除操作。在PHP中你可以用下列函数创建一个新的信号量并返回操作该信号量的句柄。如果该key指向的信号量已经存在,sem_get直接返回操作该信号量的句柄。
int sem_get (int key [, int max_acquire ][, int perm]])
$max_acquire 指明同时最多可以用几个进程进入该信号而不必等待该信号被释放(也就是最大同时处理某一资源的进程数目,一般该值均为一)。$perm指明了访问权限。
一旦你成功的拥有了一个信号量,你对它所能做的只有2种:请求、释放。当你执行释放操作时, 系统将把该信号值减一。如果小于0那就还设为0。而当你执行请求操作时,系统将把该信号值加一,如果该值大于设定的最大值那么系统将挂起你的处理进程直到其他进程释放到小于最大值为止。一般情况下最大值设为1,这样一来当一个进程获得请求时其他后面的进程只能等待它退出互斥区后释放信号量才能进入该互斥区并同时设为独占方式。这样的信号量常称为双态信号量。当然,如果初值是任意一个正数就表明有多少个共享资源单位可供共享应用。
申请、释放操作的PHP格式如下:
int sem_acquire (int sem_identifier) 申请
int sem_release (int sem_identifier) 释放
其中sem_identifier是调用sem_get的返回值(句柄)。  
一个简单的互斥协议例子
下面是一段很简单的互斥操作规程。
$semid=sem_get(0xee3,1,0666);
$shm_id = shmop_open(0xff3, "c", 0644, 100);
sem_acquire($semid);????? //申请
/* 进入临界区*/
??这里,对共享内存进行处理
sem_release($semid); ?????//释放
正如你所看到的,互斥的实现很简单:申请进入临界区,对临界区资源进行操作(比如修改共享内存)退出临界区并释放信号。这样一来就可以保证在同一个时间片中不可能有同时2个进程对同一段共享内存进行操作。因为信号量机制保证一个时间片只能由一个进程进入,其他进程必须等待当前处理的进程完成后方能进入。
临界区一般是指那些不允许同时有多个进程并发处理的代码段。
要注意的是:在PHP中必须由同一个进程释放它所占用的信号量。在一般系统中允许进程释放别的进程占用的信号。在编写临界区代码一定要小心设计资源的分配,避免A等B,B等A的死锁情况发生。  
运?用
IPC的运用是十分广泛的。比如,在不同进程间保存一个解释过的复杂的配置文件、或具体设置的用户等,以避免重复处理。我也曾经用共享内存的技术把一大批PHP脚本必须引用的一个很大的文件放入共享内存,并由此显著提升了Web服务的速度、消除了部分瓶颈。关于它的使用还有聊天室,多路广播等等。IPC的威力取决于你的想象力的大小。如果本文对你有一点点启发,那我不胜荣幸。愿意很你讨论这令人入迷的电脑技术。Email: qwyaxm@163.net

PHP 相关文章推荐
PHP 和 COM
Oct 09 PHP
PHP - Html Transfer Code
Oct 09 PHP
php self,$this,const,static,->的使用
Oct 22 PHP
二招解决php乱码问题
Mar 25 PHP
php文本转图片自动换行的方法
Mar 13 PHP
PHP+Mysql实现多关键字与多字段生成SQL语句的函数
Nov 05 PHP
PHP处理CSV表格文件的常用操作方法总结
Jul 01 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
Sep 30 PHP
浅谈PHP的数据库接口和技术
Dec 09 PHP
php事务回滚简单实现方法示例
Mar 28 PHP
利用php-cli和任务计划实现刷新token功能的方法
May 03 PHP
PHP defined()函数的使用图文详解
Jul 20 PHP
PHP利用COM对象访问SQLServer、Access
Oct 09 #PHP
新版mysql+apache+php Linux安装指南
Oct 09 #PHP
Win2000+Apache+MySql+PHP4+PERL安装使用小结
Oct 09 #PHP
用PHP将数据导入到Foxmail
Oct 09 #PHP
PHP 中的一些经验积累
Oct 09 #PHP
详细介绍PHP应用提速面面观
Oct 09 #PHP
基于PHP与XML的PDF文档生成技术
Oct 09 #PHP
You might like
深入PHP操作MongoDB的技术总结
2013/06/02 PHP
深入探讨<br />和 \r\n两者有什么区别??
2013/06/05 PHP
php将图片保存入mysql数据库失败的解决方法
2014/12/27 PHP
php使用gettimeofday函数返回当前时间并存放在关联数组里
2015/03/19 PHP
php自定义类fsocket模拟post或get请求的方法
2015/07/31 PHP
Ajax提交表单时验证码自动验证 php后端验证码检测
2016/07/20 PHP
javascript 获取url参数和script标签中获取url参数函数代码
2010/01/22 Javascript
自动设置iframe大小的jQuery代码
2013/09/11 Javascript
JavaScript程序员应该知道的45个实用技巧
2014/03/04 Javascript
jquery插件NProgress.js制作网页加载进度条
2015/06/05 Javascript
AngularJS使用ngMessages进行表单验证
2015/12/27 Javascript
Bootstrap实现登录校验表单(带验证码)
2016/06/23 Javascript
js利用appendChild对标签进行排序的实现方法
2016/10/16 Javascript
Vue数据驱动模拟实现3
2017/01/11 Javascript
H5手机端多文件上传预览插件
2017/04/21 Javascript
JS实现简单的选择题测评系统代码思路详解(demo)
2017/09/03 Javascript
vue组件暴露和.js文件暴露接口操作
2020/08/11 Javascript
Python使用pickle模块存储数据报错解决示例代码
2018/01/26 Python
python更改已存在excel文件的方法
2018/05/03 Python
python RabbitMQ 使用详细介绍(小结)
2018/11/08 Python
python使用magic模块进行文件类型识别方法
2018/12/08 Python
Opencv实现抠图背景图替换功能
2019/05/21 Python
python 画出使用分类器得到的决策边界
2019/08/21 Python
纽约JewelryAffairs珠宝店:精细金银时尚首饰
2017/02/05 全球购物
戴森台湾线上商城:Dyson Taiwan
2018/05/21 全球购物
迪拜领先运动补剂零售品牌中文站:Sporter商城
2019/08/20 全球购物
前台文员的岗位职责
2013/11/14 职场文书
中专生自我鉴定
2013/12/17 职场文书
就业意向书范文
2014/04/01 职场文书
安全生产月演讲稿
2014/05/09 职场文书
岗位安全生产责任书
2014/07/28 职场文书
我们的节日元宵节活动总结
2015/02/06 职场文书
员工表扬信怎么写
2015/05/05 职场文书
MySQL8.0.24版本Release Note的一些改进点
2021/04/22 MySQL
浅谈什么是SpringBoot异常处理自动配置的原理
2021/06/21 Java/Android
Python上下文管理器Content Manager
2021/06/26 Python