php进程间通信--共享内存

php如何实现共享内存。(注意:本示例是在linux下,请勿在windows下尝试此代码,并且必须是在php-cli模式下)

php提供了两种实现共享内存的扩展。下面我们来一一讲解。

  一、shmop 系类函数

<?php

$shm_key = ftok(__FILE__, 't');

/**
开辟一块共享内存
int $key , string $flags , int $mode , int $size
$flags: 
a:访问只读内存段
c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写
w:可读写的内存段
n:创建一个新内存段,如果该内存段已存在,则会失败
$mode: 八进制格式  0655
$size: 开辟的数据大小 字节
 */
$shm_id = shmop_open($shm_key, "c", 0655, 1024);


/**
 * 写入数据 数据必须是字符串格式 , 最后一个指偏移量
 * 注意:偏移量必须在指定的范围之内,否则写入不了
 *
 */
 
$size = shmop_write($shm_id, 'hello world', 0);
echo "write into {$size}";

//读取的范围也必须在申请的内存范围之内,否则失败
$data = shmop_read($shm_id, 0, $size);
var_dump($data);

/*
删除 只是做一个删除标志位,同时不在允许新的进程进程读取,当在没有任何进程读取时系统会自动删除
*/

shmop_delete($shm_id);

//关闭该内存段
shmop_close($shm_id);

?>

注意两点:

  1、shmop_read 函数 第2个参数 是读取的起始位置,第3个参数是要读取的长度,如果你要读取的长度小于信息长度,原信息会被截断成你指定的长度。

  2、shmop_write 函数 仅可写 字符串 内容!

二、用 Semaphore 扩展中的 sem 类函数 (用起来更方便,类似 key-value 格式)

<?php

$key = ftok(__FILE__, 'a');
$shar_key = 1;

// 创建一个共享内存
$shm_id = shm_attach($key, 1024, 0666); // resource type
if ($shm_id === false) {
    die('Unable to create the shared memory segment' . PHP_EOL);
}

//设置一个值
shm_put_var($shm_id, $shar_key, 'test');

#删除一个key
//shm_remove_var($shm_id, $shar_key);

//获取一个值
$value = shm_get_var($shm_id,  $shar_key);
var_dump($value);

//检测一个key是否存在
var_dump(shm_has_var($shm_id,  $shar_key));

//从系统中移除
shm_remove($shm_id);

//关闭和共享内存的连接
shm_detach($shm_id);
?>

shm_put_var 第三个参数 写入的值 是一个混合类型,所以没有shmop_write的局限性。

注意:$shar_key 只能是 int 型的参数。

php如何创建、操作共享内存,下面我们来看一下,他们如何在进程间通信发挥作用吧。

<?php
//共享内存通信

//1、创建共享内存区域
$shm_key = ftok(__FILE__, 't');
$shm_id = shm_attach( $shm_key, 1024, 0655 );
const SHARE_KEY = 1;
$childList = [];

//2、开3个进程 读写 该内存区域
for ( $i = 0; $i < 3; $i++ ) {

     $pid = pcntl_fork();
	 
	 if ( $pid == -1 ) {
        exit('fork fail!' . PHP_EOL);
     } else if ( $pid == 0 ) {
		 
		//子进程从共享内存块中读取 写入值 +1 写回
		 if ( shm_has_var($shm_id, SHARE_KEY) ) {
			 // 有值,加一
            $count = shm_get_var($shm_id, SHARE_KEY);
            $count ++;
            //模拟业务处理逻辑延迟
            $sec = rand( 1, 3 );
            sleep($sec);

            shm_put_var($shm_id, SHARE_KEY, $count); 
		 } else {
            // 无值,初始化
            $count = 0;
            //模拟业务处理逻辑延迟
            $sec = rand( 1, 3 );
            sleep($sec);

            shm_put_var($shm_id, SHARE_KEY, $count);
        }

        echo "child process " . getmypid() . " is writing ! now count is $count\n";

        exit( "child process " . getmypid() . " end!\n" );
	 } else {
		  $childList[$pid] = ;
	 }
	
}
 
// 等待所有子进程结束
while( !empty( $childList ) ){
    $childPid = pcntl_wait( $status );
    if ( $childPid > 0 ){
        unset( $childList[$childPid] );
    }
}


//父进程读取共享内存中的值
$count = shm_get_var($shm_id, SHARE_KEY);
echo "final count is " . $count . PHP_EOL;
 

//3、去除内存共享区域
#从系统中移除
shm_remove($shm_id);
#关闭和共享内存的连接
shm_detach($shm_id);
?>

从结果中我们可以看到,最终的 count 的值还是0。这是为什么呢?简单分析一下,不难发现,当我们开启创建进程的时候,3个子进程同时打开了 共享内存区域,此时他们几乎是同步的,所以读到的信息都是没有count值,此时他们执行自己的业务

逻辑然后将 count 为0的结果写入内存区域。这并不是我们想要的结果,三个子进程互相抢占了资源,这是不合理的,那怎么规避这个问题呢?答案是通过 信号量 !

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值