PHP共享内存

如何使用 PHP shmop 创建和操作共享内存段,使用它们存储可供其他应用程序使用的数据。

1. 创建内存段

共享内存函数类似于文件操作函数,但无需处理一个流,您将处理一个共享内存访问 ID。第一个示例就是 shmopopen 函数,它允许您打开一个现有的内存段或创建一个新内存段。此函数非常类似于经典的 fopen 函数,后者打开用于文件操作的流,返回一个资源供其他希望读取或写入该打开的流的函数使用。让我们看看 shmopopen的用法:

<?php
$key = ftok(__FILE__, ‘h‘);
$mode = ‘c‘;
$permissions = 0644;
$size = 1024;
$shmid = shmop_open($key, $mode, $permissions, $size);
?>

第一个参数($key):

系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个key值。通常情况下,该key值通过ftok函数得到, * *key是一个我们逻辑上表示共享内存段的标识。不同进程只要选择同一个Key值就可以共享同一段存储段。

第二个参数($mode):

访问模式,它类似于fopen的访问模式,有以下几种

  • 模式 “a”,它允许您访问只读内存段
  • 模式 “w”,它允许您访问可读写的内存段
  • 模式 “c”,它创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写 *模式 “n”,它创建一个新内存段,如果该内存段已存在,则会失败,返回 false,并伴随有warning: unable to attach or create shared memory segment

第三个参数($permissions):

内存段的权限。您必须在这里提供一个八进制值,它类似于UNIX操作系统文件和目录的操作权限。

第四个参数($size):

内存段大小,以字节为单位。在写入一个内存段之前,您必须在它之上分配适当的字节数。

返回结果:

此函数返回一个 ID 编号,其他函数可使用该 ID 编号操作该共享内存段。这个 ID 是共享内存访问 ID,与系统 ID 不同,它以参数的形式传递。请注意不要混淆这两者。如果失败,shmop_open 将返回 FALSE。

shmop_open成功后,使用ipcs -m, 可以查看到刚刚创建的内存段,注意 申请的内存段有严格的权限,比如用root用户申请的,普通用户就无权访问

2. 向内存段写入数据

使用 shmop_write 函数向共享内存块写入数据。此函数的使用很简单,它仅接受 3 个参数,如下所示。

<?php
//这里shmid可以延用上一段代码返回的shmid
$shmid = shmop_open(ftok(__FILE__,‘h‘), ‘c‘, 0644, 1024);
shmop_write($shmid, "Hello World!", 0);

?>

这个函数类似于 fwrite 函数, 在这里有三个参数。 * 第一个参数(shmid):是shmopopen返回的ID,它识别您操作的共享内存块。?第二个参数(shmid):是shmopopen返回的ID,它识别您操作的共享内存块。?第二个参数(data):是您希望存储的数据。 * 第三个参数($offset):是您希望开始写入的位置。默认情况下,我们始终使用 0 来表示开始写入的位置。

返回结果:此函数在失败时会返回 FALSE,在成功时会返回写入的字节数。

3. 从内存段读取数据

从共享内存段读取数据很简单。您只需要一个打开的内存段和 shmop_read 函数,它接受三个参数,如下所示:

<?php
$shmid = shmop_open(ftok(\__FILE_\_,‘h‘), ‘c‘, 0644, 1024);
shmop_write($shmid, "Hello World\!", 0);
var_dump(shmop_read($shmid, 0, 11));
?>
  • 第一个参数($shmid):是 shmop_open 返回的 ID,它识别您操作的共享内存块。
  • 第二个参数($start):是您希望从内存段读取的位置,这个参数可以始终为0, 表示数据的开头
  • 第三个参数(count):是您希望读取的字节数。一般情况下我们用shmopsize(count):是您希望读取的字节数。一般情况下我们用shmopsize(shmid),以便完整的读取它。

4. 删除内存段

shmop_delete 该函数只接收一个参数,如下所示:

<?php
$shmid = shmop_open(ftok(\__FILE_\_,‘h‘), ‘c‘, 0644, 1024);
shmop_delete($shmid);
?>

其实这个函数不会实际删除该内存段。它将该内存段标记为删除状态,因为共享内存段在有其他进程正在使用它时无法被删除。shmop_delete 函数将该内存段标记为删除,阻止任何其他进程打开它。要删除它,我们需要关闭该内存段。

5. 关闭内存段

打开一个共享内存段会 “附加” 到它。附加该内存段之后,我们可在其中进行读取和写入,但完成操作后,我们必须从它解除。

<?php
$shmid = shmop_open(ftok(\__FILE_\_,‘h‘), ‘c‘, 0644, 1024);
shmop_write($shmid, "Hello World\!", 0);
shmop_delete($shmid); shmop_close($shmid);
?>

共享内存的原子操作 - 信号控制

针对共享内存的写操作本身不是原子性的,那么当我们大量并发进行读写的时候,怎么保证原子性呢,这里要引入信号量进行控制。

PHP 也提供了内置扩展 sysvsem ,其实我们在看sysvsem 提供的一系列sem*的方法的时候,就会想到,这和上面提到的shmop*有什么区别呢,我们来看官房文档中的这一个解释:PHP already had a shared memory extension (sysvshm) written by Christian Cartus [email protected], unfortunately this extension was designed with PHP only in mind and offers high level features which are extremely bothersome for basic SHM we had in mind.

也就是说:sysvshm 扩展提供的方法在存储之前对用户的数据进行serialize处理,这里就导致这个存储的数据是无法与其它语言共享的,这一系列方法是php only的方法。

引入信号控制之后的示例:

<?php
$key = ftok(_FILE_, ‘h‘) $mode = "c";
$permissions = 0755;
$size = 1024; // 内存段的大小,单位是字节
$semid = sem_get($key); # 请求信号控制权
if (sem_acquire($semid)) {
    $shmid = shmop_open($key, ‘c‘, 0644, 1024); # 读取并写入数据
    shmop_write($shmid, ‘13800138000‘, 0); # 关闭内存块
    shmop_close($shmid); # 释放信号 sem_release($semid);
}

共享内存的操作是非常快的,在本地想要模拟实现写入冲突是非常困难的,但是本地想模拟实现写入冲突实际上是非常难的(考虑到计算机的执行速度)。在本地测试中,使用 for 循环操作时如果不使用shmop_close 关闭资源会出现无法打开共享内存的错误警告。这应该是因为正在共享内存被上一次操作占用中还没有释放导致。

原文地址:https://www.cnblogs.com/setevn/p/8616772.html

时间: 2024-10-11 04:45:29

PHP共享内存的相关文章

php 共享内存

转:php 共享内存 共享内存主要用于进程间通信 php中的共享内存有两套扩展可以实现 1.shmop  编译时需要开启 --enable-shmop 参数 实例: $shm_key = ftok(__FILE__, 't'); /** 开辟一块共享内存 int $key , string $flags , int $mode , int $size $flags: a:访问只读内存段 c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写 w:可读写的内存段 n:创建一个新内存段,如

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

一.共享内存 共享内存是最高效的通信方式,因为不需要一个进程先拷贝到内核,另一个进程在存内核中读取. 二. ipcs -m 查看共享内存 ipcrm -m 删除共享内存 三.主要函数 shmget 创建 shmctl 删除 shmat 挂接 shmdt 取消挂接 ********* man 函数名 查看***** 四.代码实现 comm.h   1 #pragma once   2 #include<stdio.h>   3 #include<stdlib.h>   4 #incl

linux共享内存之mmap

这应该可以算得上是IPC的一种,虽然效率可能并没有其它IPC方式高. 看到map很容易联想到映射.的确,mmap就是一种映射方式,将打开的文件和一段连续的内存做映射.使得对内存进行操作即可以实现对文件的读写,反过来,也就是说,可以通过这种方式来达到进程通信. mmap系列涉及三个函数. void * mmap(void *buf, size_t len, int prot, int flag, int fd, off_t offset); 此函数建立一个共享内存,prot即为权限,可选值有PRO

linux 共享内存实现

说起共享内存,一般来说会让人想起下面一些方法:1.多线程.线程之间的内存都是共享的.更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享:2.父子进程间的内存共享.父进程以MAP_SHARED|MAP_ANONYMOUS选项mmap一块匿名内存,fork之后,其子孙进程之间就能共享这块内存.这种共享内存由于受到进程父子关系的限制,一般较少使用:3.mmap文件.多个进程mmap到同一个文件,实际上就是大家在共享文件page cache中的内存.不过文件牵涉到

Linux 进程间共享内存 SYSTEMV

#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, int size, int shmflag) key取值为IPC_PRIVATE时,shmflag应为IPC_CREAT,则新建共享内存key取值不为IPC_PRIVATE则应为已创建的key值,shmflag不应包含IPC_CREAT和IPC_EXCL,且大小小于等于原共享内存大小成功则返回共享内存id,失败返回-1 void *shmat(int sh

(转载)linux下的僵尸进程处理SIGCHLD信号Linux环境进程间通信(五): 共享内存(下)

Linux环境进程间通信(五): 共享内存(下) 在共享内存(上)中,主要围绕着系统调用mmap()进行讨论的,本部分将讨论系统V共享内存,并通过实验结果对比来阐述两者的异同.系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面. 系统调用mmap()通过映射一个普通文件实现共享内存.系统V则是通过映射特殊文件系统shm中的文件实现进程间的共享内

撸代码--linux进程通信(基于共享内存)

1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候要保证子进程退出后,在删除共享内存. 4)子进程完毕读的内容. 效果展示:                 代码展示:           #include <string.h> #include <unistd.h> #include <sys/types.h> #inc

PHP 共享内存使用与信号控制

共享内存 共享内存的使用主要是为了能够在同一台机器不同的进程中共享一些数据,比如在多个 php-fpm 进程中共享当前进程的使用情况.这种通信也称为进程间通信(Inter-Process Communication),简称 IPC. PHP 内置的 shmop 扩展 (Shared Memory Operations) 提供了一系列共享内存操作的函数(可能是用的人不多吧,这一块儿的文档还没有中文翻译).在 Linux 上,这些函数直接是通过调用 shm* 系列的函数实现,而 Winodows 上

信号量学习 &amp; 共享内存同步

刚刚这篇文章学习了共享内存:http://www.cnblogs.com/charlesblc/p/6142139.html 里面也提到了共享内存,自己不进行同步,需要其他手段比如信号量来进行.那么现在就学习信号量咯. 共享内存实际编程中, 应该使用信号量, 或通过传递消息(使用管道或IPC消息), 或生成信号 的方法来提供读写之间的更有效的同步机制. 方法一.利用POSIX有名信号灯实现共享内存的同步 方法二.利用POSIX无名信号灯实现共享内存的同步 方法三.利用System V的信号灯实现

由共享内存引发的思考

1.共享内存段被映射进进程空间之后,存在于进程空间的什么位置?共享内存段最大限制是多少? 存在于进程数据段,最大限制是0x2000000Byte 将一块内存映射到两个或者多个进程地址空间.通过指针访问该共享内存区.一般通过mmap将文件映射到进程地址共享区. Linux对共享内存的实现,在2.6采用了内存映射技术.对于内存共享,主要集中在三个内核函数,他们是do_shmat,sys_shmat和sys_shmdt.其中,sys_shmat调用了do_shmat最终实现了共享内存的attach.s