一、引言

进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是,在系统调度多个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 进程及进程间通信相关推荐

  1. Python之路 34:并发与并行、锁(GIL、同步锁、死锁与递归锁)、信号量、线程队列、生消模型、进程(基础使用、进程通信、进程池、回调函数)、协程

    内容: 同步锁 死锁.递归锁 信号量和同步对象(暂时了解即可) 队列------生产者和消费者模型 进程(基础使用.进程通信.进程池.回调函数) 协程 一.并发并行与同步异步的概念 1.1.并发和并行 ...

  2. Chrome源码剖析、上--多线程模型、进程通信、进程模型

    Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很大 ...

  3. 【chrome】Chrome源码剖析、上--多线程模型、进程通信、进程模型

     Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很 ...

  4. Chrome源码剖析——多线程模型、进程通信、进程模型

    说明:本文内容由 v_JULY_v 根据 duguguiyu 的博客整理而成. 前言 1.  之所以整理此文,有两个目的:一是为了供自己学习研究之用:二是为了备份,以作日后反复研究.除此之外,无它. ...

  5. linux进程实现进程通信内存共享,Linux进程间通信 -3内存共享

    内存共享允许两个或多个不相关的进程,访问同一个逻辑内存,共享内存的具体实现,由不同进程之间共享的内存安排为同一物理内存. 过个进程就像通过malloc获取的内存一样去使用,但是需要额外的小消息来同队内 ...

  6. python实现进程通信_python进程间的通讯实现

    1:进程间通讯的方法:apply_async()非阻塞式通讯     apply()阻塞式通讯 2:使用Queue实现对Process创建的进程间通讯, Queue本身是一个消息队列程序,Queue常 ...

  7. 共享内存-父子进程、非亲缘关系进程通信

    共享内存的特点: 共享内存创建后一直存在于内核中,直到被删除或系统关闭: 共享内存和管道不一样,读取后,内容仍然存在. shm_get函数: 共享内存的创建 头文件: #include <sys ...

  8. linux 进程通信比较,浅析Linux进程通信的几种方式及其比较

    摘要:本文通过对Linux下几种主要通信方式进行概述,并结合Linux系统的系统调用对OS中的实现进行简要概述,并对其优缺点进行分析,阐述了在不同通信情况下应该选择何种通信方式进行选择. 关键词:Li ...

  9. Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结

    Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...

最新文章

  1. 腾讯宣布员工最高可申请免息借款90万!网友:应届当码农就能一线城市买房了!...
  2. MySQL优化篇:慢查询日志
  3. 工具用途_德普优化使用指南:16个工具的功能及用途(工具文)
  4. dump文件分析工具_使用这个 Python 工具分析你的 Web 服务器日志文件 | Linux 中国...
  5. buildin 字节交换
  6. XML基本知识(三)
  7. 【Python】main函数 if __name__=='__main__' 详解
  8. 1000道Python题库系列分享15(1道代码改写题)
  9. python getattr用法_python自省函数getattr的用法
  10. Start Developing iOS Apps Today系列之应用程序(七)
  11. vc++无进程式线程插入穿墙技术实现
  12. python语言通过import_python语言的引入(import)机制简述
  13. 多视角子空间学习系列之 CCA 典型相关分析
  14. 微信公众号消息推送教程
  15. 关于复数i本质的探讨
  16. 如何处理pagefile.sys占用太多C盘空间
  17. 七夕将至,20行js代码给女友做个卡通P图微信机器人
  18. 用the_excerpt处理中文文章字数限制的方法
  19. c语言 解元二次函数的源代码,学霸强推,高中数学万能解题方法,对数学一筹莫展的你必看!...
  20. PPT“备注”内容字体可以修改颜色也能直接看到修改效果

热门文章

  1. python里的符号区别_Python中的方括号和点符号有什么区别?
  2. python中输出菱形_用python打印菱形的实操方法和代码
  3. 项目管理指标_项目经理必掌握的九大项目管理问题
  4. 抽奖 | 送树莓派PICO开发板、机械键盘、声控鼠标
  5. 电赛 | 电源题软件如何准备?
  6. php系统函数代码,PHP自定义函数+系统函数库(代码示例)
  7. java html api 百度云,Javase-6.0_中文API_HTML(最新更新)
  8. js 根据条件禁止复选框_element-ui多选框根据不同条件禁用?
  9. tomcat的wget链接_Linux(jdk安装tomcat安装nginx安装gcc/wget)
  10. GenXus学习笔记——Transaction的建立