基本用法

示例 #1 共享内存操作概述

<?php

// 创建一个系统 ID 为 0xff3 的 100 字节共享内存块
$shm_id = shmop_open(0xff3, "c", 0644, 100);
if (!
$shm_id) {
echo
"无法创建共享内存段\n";
}

// 获取共享内存块的大小
$shm_size = shmop_size($shm_id);
echo
"SHM 块大小: " . $shm_size . " 已创建。\n";

// 让我们将测试字符串写入共享内存
$shm_bytes_written = shmop_write($shm_id, "my shared memory block", 0);
if (
$shm_bytes_written != strlen("my shared memory block")) {
echo
"无法写入整个长度的数据\n";
}

// 现在让我们读回字符串
$my_string = shmop_read($shm_id, 0, $shm_size);
if (!
$my_string) {
echo
"无法从共享内存块读取\n";
}
echo
"共享内存中的数据为: " . $my_string . "\n";

// 现在让我们删除块并关闭共享内存段
if (!shmop_delete($shm_id)) {
echo
"无法标记共享内存块以供删除。";
}
shmop_close($shm_id);

?>

添加笔记

用户贡献笔记 1 条笔记

3
匿名
6 年前
SHMOP 实现的简单类。

# 警告 #

您只能写/读一个方向。如果您尝试同时读写,您将获得损坏的数据。 (它像 STD 输入/输出一样工作)
如果您需要双向通信,请创建 2 个 shmop 类实例。
不要尝试为某个 shmid 附加多个阅读器或写入器,您将获得损坏的数据。此类使用笨拙的自旋锁来提高速度,而不是真正的原子操作。您可以使用 flock 添加信号量,但它非常慢。 (~x3)

基准测试

每秒读取次数:6316 每秒数据量:6.17 gb

<?php
########################
# shmopwriter.php
########################

$blockSize = 1024 * 1024 * 100;
$data = random_bytes($blockSize);

try
{
$shm = new SHMOP('shmopwriter.php', 'c', 644, $blockSize);

while(
1)
{
if(!
$shm->canWrite())
continue;

$shm->write($data);
}

$shm->close();

} catch (
Exception $e) {
echo
'Error: ', $e->getMessage(), PHP_EOL;
exit;
}

########################

########################
# shmopreader.php
########################

$blockSize = 1024 * 1024 * 100;
$shm = new SHMOP('shmopwriter.php', 'c', 644, $blockSize);
$readsMT = 0;
$readsPS = 0;

while(!
$shm->eof())
{
$times = microtime(true);

if((
$data = $shm->read()) === false)
continue;

$readsPS++;
$readsMT += round(((microtime(true) - $times ) * 1000), 3);

if(
$readsMT > 1000)
{
echo
'Reads per sec: ', $readsPS, ' Data size per sec: ', convert($blockSize * $readsPS), PHP_EOL;
$readsPS = 0;
$readsMT = 0;
}
}

function
convert($size)
{
$unit=array('b','kb','mb','gb','tb','pb');
return @
round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
########################

########################
# shmop.class.php
########################

class SHMOP
{
private
$shmId;
private
$shmHeaderSize;
private
$shmHeaderOffset;
private
$shmBlockSize;
private
$shmMaxBlockSize;

function
__construct(string $pathname, string $flags, int $mode, int $size)
{
$this->shmHeaderSize = strlen($size);
$this->shmHeaderOffset = $this->shmHeaderSize + 1;
$this->shmMaxBlockSize = $size;
$this->shmBlockSize = $size + $this->shmHeaderOffset + 1;

$this->shmId = shmop_open(ftok($pathname, 's'), $flags, $mode, $this->shmBlockSize);

if(!
$this->shmId)
throw new
Exception('shmop_open error');
}

function
__destruct()
{
if(!
$this->shmId)
return;

$this->close();
}

public function
read()
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) === "\0")
return
false;

// Get Header
$dataSize = (int)shmop_read($this->shmId, 1, $this->shmHeaderSize);

$data = shmop_read($this->shmId, $this->shmHeaderOffset, $dataSize);
// release spinlock
shmop_write($this->shmId, "\0", 0);
return
$data;
}

public function
write(string $data)
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) !== "\0")
return
false;

$dataSize = strlen($data);

if(
$dataSize < 1)
throw new
Exception('dataSize < 1');

if(
$dataSize > $this->shmMaxBlockSize)
throw new
Exception('dataSize > shmMaxBlockSize: '. $this->shmMaxBlockSize);

// pack very slow use kludge
$dataSize .= "\0";

// Write Header
shmop_write($this->shmId, $dataSize, 1);
// Write Data
shmop_write($this->shmId, $data, $this->shmHeaderOffset);
// Write spinlock
shmop_write($this->shmId, "\1", 0);
return
true;
}

public function
eof()
{
return (
shmop_read($this->shmId, 0, 1) === "\2") ? true : false;
}

public function
sendeof()
{
// Check SpinLock
if(shmop_read($this->shmId, 0, 1) !== "\0")
return
false;

shmop_write($this->shmId, "\2", 0);
return
true;
}

public function
canWrite()
{
// Check SpinLock
return (shmop_read($this->shmId, 0, 1) === "\0") ? true : false;
}

public function
close()
{
return @
shmop_close($this->shmId);
}

private function
delete()
{
$del = @shmop_delete($this->shmId);

if(
$del === false)
return
false;

return @
shmop_close($this->shmId);
}
}

?>
To Top