设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间00 现在时间00 缓存数据 父母亲存在的意义不是给予孩子舒适和富裕的生活,而是,当你想到你的父母时,你的内心会充满力量,会感受到温暖,从而拥有克服困难的勇气和能力,以此获得人生真正的乐趣和自由。晚安!

父母亲存在的意义不是给予孩子舒适和富裕的生活,而是,当你想到你的父母时,你的内心会充满力量,会感受到温暖,从而拥有克服困难的勇气和能力,以此获得人生真正的乐趣和自由。晚安!

查看: 843|回复: 1

php进程通信之共享内存详细讲解

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:234
  • 打卡月天数:0
  • 打卡总奖励:3992
  • 最近打卡:2025-04-23 05:27:37
等级头衔

等級:晓枫资讯-上等兵

在线时间
5 小时

积分成就
威望
0
贡献
470
主题
401
精华
0
金钱
5330
积分
941
注册时间
2023-1-8
最后登录
2025-5-31

发表于 2023-2-12 19:09:54 | 显示全部楼层 |阅读模式
常见进程通信方式

201007d64y64udpu6h6udf.png


system V共享内存

现代操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A 和 进程 B 的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。
共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,不需要经过数次的拷贝(比如从输入缓冲区中拷贝到文件中、再拷贝到输出缓冲区中等),大大提高了进程间通信的速度。
在所有进程间通信的方式中共享内存的效率是最高的。
共享内存操作默认不阻塞,如果多个进程同时读写共享内存,可能出现数据混乱,共享内存需要借助其他机制来保证进程间的数据同步,比如:上期讲信号量,共享内存内部没有提供这种同步机制。
201007uryyq78or8i911be.png

通过上图可知,共享内存是通过将不同进程的虚拟内存地址映射到相同的物理内存地址来实现的
页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页(虚拟内存)与物理页帧(物理内存)的对应关系。 每一个进程都拥有一个自己的页表。

php使用共享内存

php 提供了两套操作共享内存的扩展,两套扩展都实现了相同的功能,用哪个看你喜欢
https://www.php.net/manual/en/ref.shmop.php
https://www.php.net/manual/en/ref.sem.php
201008n1az4616n64sg63p.png


共享内存基本函数使用
  1. <?php
  2. $key = ftok('demo1.php','x'); //将路径名和项目标识符转换为System V IPC键
  3. $shm_id = shm_attach($key,1024,0666);//创建一个大小为1024字节的共享内存存段,权限为0666,并且将共享内存映射关联到当前进程的地址空间
  4. shm_put_var($shm_id,1,'hello world');//往共享内存里写入数据
  5. echo "共享内存:".shm_get_var($shm_id,1).PHP_EOL;//读取共享内存里数据
复制代码
201008xaasnnapisovniat.png


父子进程通信
  1. <?php
  2. $key = ftok('demo4.php','x');
  3. // $shm_id 它对应当前进程的地址空间,实际是映射连接了系统分配的共享区域(共享内存)
  4. $shm_id = shm_attach($key,1024,0666);//创建一个大小为1024字节的共享内存存段,权限为0666,并且将共享内存映射关联到当前进程的地址空间
  5. $pid = pcntl_fork();// fork 子进程
  6. if($pid == 0){//子进程运行逻辑
  7.    echo shm_get_var($shm_id,1).PHP_EOL;//读取共享内存数据
  8.         exit(0);
  9. }
  10. //父进程运行逻辑
  11. shm_put_var($shm_id,1,'hello world');//写入数据到共享内存,第三个参数可以传入任意数据类型
  12. pcntl_wait($status);//等待子进程退出释放资源,防止僵尸进程
  13. // 删除共享内存是有顺序的,先remove后detach,顺序反过来php可能会报错
  14. shm_remove($shm_id);//从系统中移除共享内存
  15. shm_detach($shm_id);//断开进程与共享内存的映射关系
复制代码
201008s8p6k8vp5lxacl5p.png


配合信号量使用
  1. <?php
  2. // sem key
  3. $sem_key = ftok( __FILE__, 'b' );//信号量key
  4. $sem_id = sem_get( $sem_key );//获取信号量
  5. // shm key
  6. $shm_key = ftok( __FILE__, 'm' );//共享内存key
  7. $shm_id = shm_attach( $shm_key, 1024, 0666 );//创建一个大小为1024字节的共享内存存段,权限为0666,并且将共享内存映射关联到当前进程的地址空间
  8. $child_pid = [];
  9. // fork 2 子进程
  10. for( $i = 1; $i <= 2; $i++ ){
  11.   $pid = pcntl_fork();  
  12.   if( $pid < 0 ){
  13.     exit();
  14.   } else if( 0 == $pid ) {//子进程运行逻辑
  15.         // 获取锁
  16.         sem_acquire( $sem_id );
  17.         // 检测共享内存是否有值
  18.         if( shm_has_var( $shm_id, 1) ){
  19.           //shm_get_var第二参数必须是int型
  20.           $counter = shm_get_var( $shm_id, 1);
  21.           $counter += 1;
  22.           shm_put_var( $shm_id, 1, $counter );//写入共享内存
  23.         } else {
  24.           $counter = 1;
  25.           shm_put_var( $shm_id, 1, $counter );//写入共享内存
  26.         }
  27.         // 释放锁,一定要记得释放,不然就一直会被阻锁死
  28.         sem_release( $sem_id );
  29.         exit;
  30.   } else if( $pid > 0 ) {//父进程运行逻辑
  31.     $child_pid[] = $pid;
  32.   }
  33. }
  34. while( !empty( $child_pid ) ){
  35.   foreach( $child_pid as $pid_key => $pid_item ){
  36.         $wait_result=pcntl_waitpid( $pid_item, $status, WNOHANG );
  37.         //必须判断子进程回收的状态,如果不加判断,第一次两个子进程返回都是0,直接unset后会无法进入while,导致僵尸进程
  38.         if($wait_result == -1 || $wait_result > 0)
  39.         unset( $child_pid[ $pid_key ] );
  40.   }
  41. }
  42. // 休眠2秒钟,2个子进程都执行完毕了
  43. sleep( 2 );
  44. echo '最终结果'.shm_get_var( $shm_id, 1 ).PHP_EOL;
  45. // 删除共享内存是有顺序的,先remove后detach,顺序反过来php可能会报错
  46. shm_remove( $shm_id );
  47. shm_detach( $shm_id );
复制代码
运行结果:
201008stdt1oyoano1odtb.png

如果不使用信号量,运行结果有一定概率会产生1而不是2。但是只要加入信号量sem,就一定保证100%是2,绝对不会出现其他数值。

非血缘关系进程共享内存通信

我们使用php 提供的另一套扩展来实现
写进程
  1. <?php
  2. $key = ftok('a.php','x');
  3. $shm_id = shmop_open($key,'c',0664,1204);//创建一个大小为1024字节的共享内存存段,权限为0666,并且将共享内存映射关联到当前进程的地址空间, 第二个参数为 'c' 表示共享内存段不存在就创建,存在就直接连接打开
  4. shmop_write($shm_id,'学无止境',0); // 写入数据 ,第三个参数代表写入数据的偏移量
复制代码
读进程
  1. <?php
  2. $key = ftok('a.php','x');
  3. $shm_id = shmop_open($key,'c',0664,1204);//创建一个大小为1024字节的共享内存存段,权限为0666,并且将共享内存映射关联到当前进程的地址空间, 第二个参数为 'c' 表示共享内存段不存在就创建,存在就直接连接打开
  4. echo shmop_read($shm_id,0,20).PHP_EOL; //读取共享段内容,第二个参数读取内存偏移量,第三个参数是要读取的字节数
  5. shmop_delete($shm_id);//从系统中删除共享内存段
复制代码
201008bhovvxubuihmnzhv.png


共享内存的特性

生命周期跟随操作系统
可以通过
  1. ipcs
复制代码
命令查看共享内存
201008q72wgpggap9weq29.png

201009mm18iricxrapm7wf.png

共享内存采用的是覆盖写的方式,读的时候,是访问地址。
覆盖写可以理解为,再次往共享内存中写的时候,会先将共享内存中的内容清空,再写入。
读的时候, 是访问地址,区别于管道是将数据读走了,而在共享内存中读的时候并没有将数据读走,仅仅是访问地址。
到此这篇关于php进程通信之共享内存详细讲解的文章就介绍到这了,更多相关php共享内存内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
26
积分
32
注册时间
2022-12-24
最后登录
2022-12-24

发表于 昨天 23:59 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表