php 父子进程通信,PHP 进程及进程间通信
一、引言
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是,在系统调度多个cpu的时候,一个程序的基本单元。进程对于大多数的语言都不是一个陌生的概念,作为"世界上最好的语言PHP"当然也例外。
二、环境
php中的进程是以扩展的形式来完成。通过这些扩展,我们能够很轻松的完成进程的一系列动作。
pcntl扩展:主要的进程扩展,完成进程创建于等待操作。
posix扩展:完成posix兼容机通用api,如获取进程id,杀死进程等。
sysvmsg扩展:实现system v方式的进程间通信之消息队列。
sysvsem扩展:实现system v方式的信号量。
sysvshm扩展:实现system v方式的共享内存。
sockets扩展:实现socket通信。
这些扩展只能在linux/mac中使用,window下是不支持。最后建议php版本为5.5+。
三、简单的例子
一个简单的PHP多进程例子,该例子中,一个子进程,一个父进程。子进程输出5次,退出程序。
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
$pid = pcntl_fork();
if ( $pid == -1) {
// 创建失败
exit("fork progress error!\n");
} else if ($pid == 0) {
// 子进程执行程序
$pid = posix_getpid();
$repeatNum = 5;
for ( $i = 1; $i <= $repeatnum;="" $i++)="" {="" echo="" "({$pid})child="" progress="" is="" running!="" {$i}="" \n";="" $rand="rand(1,3);" sleep($rand);="" }="" exit("({$pid})child="" end!\n");="" else="" 父进程执行程序="" $childlist[$pid]="1;" 等待子进程结束="" pcntl_wait($status);="" "({$parentpid})main="" end!";<="" code="">复制代码
完美,终于创建了一个子进程,一个父进程。完了么?没有,各个进程之间相互独立的,没有任何交集,使用范围严重受到现在。怎么办,哪就进程间通信(interprogress communication)呗。
四、进程间通信(IPC)
通常linux中的进程通信方式有:消息队列、信号量、共享内存、信号、管道、socket。
1.消息队列
消息队列是存放在内存中的一个队列。如下代码将创建3个生产者子进程,2个消费者子进程。这5个进程将通过消息队列通信。
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";$childList = array();
// 创建消息队列,以及定义消息类型(类似于数据库中的库)
$id = ftok(__FILE__,'m');
$msgQueue = msg_get_queue($id);
const MSG_TYPE = 1;
// 生产者
function producer(){
global $msgQueue;
$pid = posix_getpid();
$repeatNum = 5;
for ( $i = 1; $i <= $repeatnum;="" $i++)="" {="" $str="({$pid})progress create! {$i}" ;="" msg_send($msgqueue,msg_type,$str);="" $rand="rand(1,3);" sleep($rand);="" }="" 消费者="" function="" consumer(){="" global="" $msgqueue;="" $pid="posix_getpid();" $repeatnum="6;" for="" (="" $i="1;" <="$repeatNum;" $rel="msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message);" echo="" "{$message}="" |="" consumer({$pid})="" destroy="" \n";="" createprogress($callback){="" if="" -1)="" 创建失败="" exit("fork="" progress="" error!\n");="" else="" ($pid="=" 0)="" 子进程执行程序="" $callback();="" exit("({$pid})child="" end!\n");="" }else{="" 父进程执行程序="" return="" $pid;="" 3个写进程="" ($i="0;" 3;="" ++="" )="" $childlist[$pid]="1;" "create="" producer="" child="" progress:="" {$pid}="" 2个写进程="" 2;="" consumer="" 等待所有子进程结束="" while(!empty($childlist)){="" $childpid="pcntl_wait($status);" ($childpid=""> 0){
unset($childList[$childPid]);
}
}
echo "({$parentPid})main progress end!\n";复制代码
由于消息队列去数据是,只有一个进程能去到,所以不需要额外的锁或信号量。
2. 信号量与共享内存
信号量:是系统提供的一种原子操作,一个信号量,同时只有你个进程能操作。一个进程获得了某个信号量,就必须被该进程释放掉。
共享内存:是系统在内存中开辟的一块公共的内存区域,任何一个进程都可以访问,在同一时刻,可以有多个进程访问该区域,为了保证数据的一致性,需要对该内存区域加锁或信号量。
以下,创建多个进程修改内存中的同一个值。
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
// 创建共享内存,创建信号量,定义共享key
$shm_id = ftok(__FILE__,'m');
$sem_id = ftok(__FILE__,'s');
$shareMemory = shm_attach($shm_id);
$signal = sem_get($sem_id);
const SHARE_KEY = 1;
// 生产者
function producer(){
global $shareMemory;
global $signal;
$pid = posix_getpid();
$repeatNum = 5;
for ( $i = 1; $i <= $repeatnum;="" $i++)="" {="" 获得信号量="" sem_acquire($signal);="" if="" (shm_has_var($sharememory,share_key)){="" 有值,加一="" $count="shm_get_var($shareMemory,SHARE_KEY);" ++;="" shm_put_var($sharememory,share_key,$count);="" echo="" "({$pid})="" count:="" {$count}\n";="" }else{="" 无值,初始化="" shm_put_var($sharememory,share_key,0);="" 0\n";="" }="" 用完释放="" sem_release($signal);="" $rand="rand(1,3);" sleep($rand);="" function="" createprogress($callback){="" $pid="pcntl_fork();" (="" -1)="" 创建失败="" exit("fork="" progress="" error!\n");="" else="" ($pid="=" 0)="" 子进程执行程序="" $callback();="" exit("({$pid})child="" end!\n");="" 父进程执行程序="" return="" $pid;="" 3个写进程="" for="" ($i="0;" $i="" <="" 3;="" ++="" )="" $childlist[$pid]="1;" "create="" producer="" child="" progress:="" {$pid}="" \n";="" 等待所有子进程结束="" while(!empty($childlist)){="" $childpid="pcntl_wait($status);" ($childpid=""> 0){
unset($childList[$childPid]);
}
}
// 释放共享内存与信号量
shm_remove($shareMemory);
sem_remove($signal);
echo "({$parentPid})main progress end!\n";复制代码
3.信号
信号是一种系统调用。通常我们用的kill命令就是发送某个信号给某个进程的。具体有哪些信号可以在liunx/mac中运行kill -l查看。下面这个例子中,父进程等待5秒钟,向子进程发送sigint信号。子进程捕获信号,掉信号处理函数处理。
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
// 定义一个信号处理函数
function sighandler($signo) {
$pid = posix_getpid();
echo "{$pid} progress,oh no ,I'm killed!\n";
exit(1);
}
$pid = pcntl_fork();
if ( $pid == -1) {
// 创建失败
exit("fork progress error!\n");
} else if ($pid == 0) {
// 子进程执行程序
// 注册信号处理函数
declare(ticks=10);
pcntl_signal(SIGINT, "sighandler");
$pid = posix_getpid();
while(true){
echo "{$pid} child progress is running!\n";
sleep(1);
}
exit("({$pid})child progress end!\n");
}else{
// 父进程执行程序
$childList[$pid] = 1;
// 5秒后,父进程向子进程发送sigint信号.
sleep(5);
posix_kill($pid,SIGINT);
sleep(5);
}
echo "({$parentPid})main progress end!\n";复制代码
4.管道(有名管道)
管道是比较常用的多进程通信手段,管道分为无名管道与有名管道,无名管道只能用于具有亲缘关系的进程间通信,而有名管道可以用于同一主机上任意进程。这里只介绍有名管道。下面的例子,子进程写入数据,父进程读取数据。
// 定义管道路径,与创建管道
$pipe_path = '/data/test.pipe';
if(!file_exists($pipe_path)){
if(!posix_mkfifo($pipe_path,0664)){
exit("create pipe error!");
}
}
$pid = pcntl_fork();
if($pid == 0){
// 子进程,向管道写数据
$file = fopen($pipe_path,'w');
while (true){
fwrite($file,'hello world');
$rand = rand(1,3);
sleep($rand);
}
exit('child end!');
}else{
// 父进程,从管道读数据
$file = fopen($pipe_path,'r');
while (true){
$rel = fread($file,20);
echo "{$rel}\n";
$rand = rand(1,2);
sleep($rand);
}
}复制代码
5.socket
socket即我们常说的套接字编程。这个待补充。
php 父子进程通信,PHP 进程及进程间通信相关推荐
- Python之路 34:并发与并行、锁(GIL、同步锁、死锁与递归锁)、信号量、线程队列、生消模型、进程(基础使用、进程通信、进程池、回调函数)、协程
内容: 同步锁 死锁.递归锁 信号量和同步对象(暂时了解即可) 队列------生产者和消费者模型 进程(基础使用.进程通信.进程池.回调函数) 协程 一.并发并行与同步异步的概念 1.1.并发和并行 ...
- Chrome源码剖析、上--多线程模型、进程通信、进程模型
Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很大 ...
- 【chrome】Chrome源码剖析、上--多线程模型、进程通信、进程模型
Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很 ...
- Chrome源码剖析——多线程模型、进程通信、进程模型
说明:本文内容由 v_JULY_v 根据 duguguiyu 的博客整理而成. 前言 1. 之所以整理此文,有两个目的:一是为了供自己学习研究之用:二是为了备份,以作日后反复研究.除此之外,无它. ...
- linux进程实现进程通信内存共享,Linux进程间通信 -3内存共享
内存共享允许两个或多个不相关的进程,访问同一个逻辑内存,共享内存的具体实现,由不同进程之间共享的内存安排为同一物理内存. 过个进程就像通过malloc获取的内存一样去使用,但是需要额外的小消息来同队内 ...
- python实现进程通信_python进程间的通讯实现
1:进程间通讯的方法:apply_async()非阻塞式通讯 apply()阻塞式通讯 2:使用Queue实现对Process创建的进程间通讯, Queue本身是一个消息队列程序,Queue常 ...
- 共享内存-父子进程、非亲缘关系进程通信
共享内存的特点: 共享内存创建后一直存在于内核中,直到被删除或系统关闭: 共享内存和管道不一样,读取后,内容仍然存在. shm_get函数: 共享内存的创建 头文件: #include <sys ...
- linux 进程通信比较,浅析Linux进程通信的几种方式及其比较
摘要:本文通过对Linux下几种主要通信方式进行概述,并结合Linux系统的系统调用对OS中的实现进行简要概述,并对其优缺点进行分析,阐述了在不同通信情况下应该选择何种通信方式进行选择. 关键词:Li ...
- Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结
Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...
最新文章
- 腾讯宣布员工最高可申请免息借款90万!网友:应届当码农就能一线城市买房了!...
- MySQL优化篇:慢查询日志
- 工具用途_德普优化使用指南:16个工具的功能及用途(工具文)
- dump文件分析工具_使用这个 Python 工具分析你的 Web 服务器日志文件 | Linux 中国...
- buildin 字节交换
- XML基本知识(三)
- 【Python】main函数 if __name__=='__main__' 详解
- 1000道Python题库系列分享15(1道代码改写题)
- python getattr用法_python自省函数getattr的用法
- Start Developing iOS Apps Today系列之应用程序(七)
- vc++无进程式线程插入穿墙技术实现
- python语言通过import_python语言的引入(import)机制简述
- 多视角子空间学习系列之 CCA 典型相关分析
- 微信公众号消息推送教程
- 关于复数i本质的探讨
- 如何处理pagefile.sys占用太多C盘空间
- 七夕将至,20行js代码给女友做个卡通P图微信机器人
- 用the_excerpt处理中文文章字数限制的方法
- c语言 解元二次函数的源代码,学霸强推,高中数学万能解题方法,对数学一筹莫展的你必看!...
- PPT“备注”内容字体可以修改颜色也能直接看到修改效果
热门文章
- python里的符号区别_Python中的方括号和点符号有什么区别?
- python中输出菱形_用python打印菱形的实操方法和代码
- 项目管理指标_项目经理必掌握的九大项目管理问题
- 抽奖 | 送树莓派PICO开发板、机械键盘、声控鼠标
- 电赛 | 电源题软件如何准备?
- php系统函数代码,PHP自定义函数+系统函数库(代码示例)
- java html api 百度云,Javase-6.0_中文API_HTML(最新更新)
- js 根据条件禁止复选框_element-ui多选框根据不同条件禁用?
- tomcat的wget链接_Linux(jdk安装tomcat安装nginx安装gcc/wget)
- GenXus学习笔记——Transaction的建立