1.共享内存的介绍
共享内存是最高效的IPC机制,它不涉及进程之间的任何数据传输。每个进程都可以访问一块共享的区域进行读写操作。Linux的共享API,定义在sys/shm.h头文件里,共享内存的操作分为3个步骤:
1.创建或获取共享内存
2.将共享内存与进程地址关联
3. 使用完之后,与进程分离 。
Linux平台,可以通过 ipcs -m 查看共享内存的使用情况

2.PHP中使用共享内存的条件
php中支持两种共享内存的操作,分别为Shared Memory和Semaphore,前者在编译的时候加上 –enable-shmop 参数,后者支持共享内存、信号量、消息队列等编译参数分别为 –enable-sysvsem 、 –enable-sysvshm 、 –enable-sysvmsg 。这几种共享内存的方式都是基于System V系统的。
3.使用Shared Memory的演示
<?php
$shm_key = ftok(__FILE__, 's');
$memory_size = 10;
$max_num = 10;
$shm_id = shmop_open($shm_key, 'c', 0644, $memory_size);
$child = [];
$pid = pcntl_fork();
if ($pid == -1) {
exit;
} else if ($pid) {
$child[] = $pid;
} else {
$res = shmop_read($shm_id, 0, $memory_size);
$i = 0;
if (empty(trim($res))) {
while($i < $max_num+1) {
shmop_write($shm_id, $i++ , 0);
printf('Pid:%d 写入数据:%d'.PHP_EOL, posix_getpid(), $i);
sleep(1);
}
}
exit;
}
while( ($val = (int)trim(shmop_read($shm_id, 0, $memory_size))) < $max_num) {
printf('Pid:%d 读取数据:%d'.PHP_EOL, posix_getpid(), $val);
sleep(1);
}
while(count($child) > 0) {
foreach($child as $k => $pid) {
$res = pcntl_waitpid($pid, $status, WNOHANG);
if ($res == -1 || $res > 0) {
unset($child[$k]);
}
}
}
shmop_delete($shm_id);
shmop_close($shm_id);

4.多进程并发操作共享内存的使用
<?php
const KEY = 1; // int
$memory_size = 100; //byte
$shm_id = ftok(__FILE__, 's');
$memory = shm_attach($shm_id, $memory_size, 0666);
if (!$memory) return ;
$sem_id = ftok(__FILE__, 'c');
$signal = sem_get($shm_id);
$child = [];
$max = 1000;
for($i = 0; $i < 3; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
exit;
} else if ($pid) {
$child[] = $pid;
} else {
while (true) {
sem_acquire($signal);
if (shm_has_var($memory, KEY)) {
$val = shm_get_var($memory, KEY);
if ($val < $max) {
printf('Pid:%d 读取数据:%d' . PHP_EOL, posix_getpid(), $val);
shm_put_var($memory, KEY, ++$val);
} else {
sem_release($signal);
break;
}
} else {
shm_put_var($memory, KEY,0);
printf('Pid:%d 第一次写入数据:%d' . PHP_EOL, posix_getpid(), 0);
}
sem_release($signal);
}
exit;
}
}
while (count($child) > 0) {
foreach ($child as $k => $pid) {
$res = pcntl_waitpid($pid, $status, WNOHANG);
if ($res == -1 || $res > 0) {
unset($child[$k]);
}
}
}
shm_remove($memory);
sem_remove($signal);

5.对于信号量的补充
信号量(Semaphore)的概念是Dijkstra在1965年提出的,它解决了多进程并发操作共享资源而产生竞态条件的问题。其主要思路就是产生一块由信号量维护的临界区 (类似加锁的概念) ,在临界区内的操作是独占的。
假设有信号量SV,则对它的P(消耗资源)、V(释放资源)操作如下
P操作:如果SV>0,则SV-1, 如果SV==0, 则阻塞进程。
V操作:如果其他进程因为等待SV而处于阻塞状态,则唤醒。如果没有,则SV+1
如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。