PHP 8.4.2 Released!

基本的な使用法

例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);

?>

add a note

User Contributed Notes 1 note

up
2
Anonymous
6 years ago
Simple class for SHMOP implementation.

# Warning #

You can write/read only one direction. If you try read and write at the same time you get corrupt data. (Its works like STD in/out)
If you need bi-directional communication create 2 instance of shmop class.
Don't try attach more than one readers or writers for some shmid, you get corrupt data. This class use kludged spinlocks for improve speed, and not real atomic operations. You can add semaphore with flock, but it very slow. (~x3)

Benchmark:

Reads per sec: 6316 Data size per sec: 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