在单独的一个PHP进程中读写、创建、删除共享内存方面上你应该没有问题了。但是实际运行中不可能只是一个PHP进程在运行中。如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题--著名的并行和互斥问题。比如说有2个进程同时需要对同一段内存进行读写。当两个进程同时执行写入操作时,你将得到一个错误的数据,因为该段内存将之可能是最后执行的进程的内容,甚至是由2个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。为了解决这个问题,我们必须引入互斥机制。互斥机制在很多操作系统的教材上都有专门讲述,这里不多重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另外一种进程间(IPC)的方式,它同其他IPC机构(管道、FIFO、消息队列)不同。

说到信号量可能大家都很陌生,作为php肯定知道mysql、redis中的锁,当然还有php文件锁。说白了就是锁,用来解决进程(线程同步的问题),访问前获取锁(获取不到则等待),访问后释放锁。

信号量的作用就是,考虑是否有多个进程同时写入数据到共享内存的情况,是否需要避免冲突。

举一个生活中的例子:以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

记得给环境开启两个扩展【enable-shmop --enable-sysvsem】

因为php默认不支持这些函数,所以需要重编译php。如要使用:
System V信号量,编译时加上 –enable-sysvsem
System V共享内存,编译时加上 –enable-sysvshm
System V消息队列,编译时加上 –enable-sysvmsg
Shared Memory,编译时加上 –enable-shmop

信号量系列函数

<?php
//1、创建信号量唯一标识符
$key = 0x4337b101;
//2、创建信号量资源ID
$sem_resouce_id = sem_get($key);
//3、接受信号量
sem_acqure($sem_resource_id);
//4、释放信号量
sem_release($sem_resource_id);
//5、销毁信号量
sem_remove($sem_resource_id);

简单小案例

<?php

$key = 0x4337b101;
$sem_id = sem_get($key);
//请求信号控制权
if (sem_acquire($sem_id)) {
$shm_id = shmop_open($key, 'c', , );
//读取并写入数据
$count = (int) shmop_read($shm_id, , ) + ;
shmop_write($shm_id, str_pad($count, , '', STR_PAD_LEFT), );
// echo shmop_read($shm_id, 0, 8);
//关闭内存块
shmop_close($shm_id);
//释放信号
sem_release($sem_id);
}

如果出现报错:Warning: sem_release(): SysV semaphore 140680297324568 (key 0x4337b101) is not currently acquired in /usr/local/nginx/html/index.php on line 38

那是因为没有获得锁~

在Linux下命令观察,查看系统共享内存,信号量,队列

# ipcs

# ipcs -s  //单独查看信号量的话,使用ipcs -s命令

稍微复杂的案例

<?php
//创建共享内存区域
$shm_key = ftok(__FILE__, 'a');
$shm_id = shm_attach($shm_key, , ); //var_dump($shm_id);die(); resource(4) of type (sysvshm)
const SHARE_KEY = ;
$child_list = []; //加入信号量
$sem_id = ftok(__FILE__, 'b');
$signal = sem_get($sem_id); //$signal resource(5) of type (sysvsem) for ($i = ; $i < ; $i++) {
$pid = pcntl_fork();
if ($pid == -) {
exit("Fork fail!".PHP_EOL);
} elseif ($pid == ) {
//获取信号量
sem_acquire($signal);
if (shm_has_var($shm_id,SHARE_KEY)) {
$count = shm_get_var($shm_id, SHARE_KEY);
$count++;
//模拟业务处理
$sec = rand(, );
sleep($sec);
shm_put_var($shm_id, SHARE_KEY, $count);
} else {
$count = ;
$sec = rand(, );
sleep($sec);
shm_put_var($shm_id, SHARE_KEY, $count);
} echo "child process: ".getmypid()." is writing! now count is: $count ".PHP_EOL; //释放信号量
sem_release($signal);
exit("child process".getmypid()."end".PHP_EOL);
} else {
$child_list[] = $pid;
}
} while (count($child_list) > ) {
foreach ($child_list as $key => $pid) {
$status = pcntl_waitpid($pid, $status);
if ($status > || $status == -) {
unset($child_list[$key]);
}
}
sleep();
} $count = shm_get_var($shm_id, SHARE_KEY);
echo " $count ".PHP_EOL; //销毁信号量
sem_remove($signal); shm_remove($shm_id);
shm_detach($shm_id);

实际运用中根据场景灵活运用就可以了~

作为phper既然了解共享内存函数shmop的使用方法,那么就必须要了解一下信号量是什么,以及信号量使用的代码案例的更多相关文章

  1. linux实现共享内存同步的四种方法

    https://blog.csdn.net/sunxiaopengsun/article/details/79869115 本文主要对实现共享内存同步的四种方法进行了介绍. 共享内存是一种最为高效的进 ...

  2. php 共享内存学习(shmop函数)

    问题:希望可以在进程间共享变量,为共享数据提供快速访问 解决方案:除了可以使用APC模块,还可以用shmop或System V共享内存 //创建键 //将一个可访问的文件路径名转换为一个可供 shmo ...

  3. 创建共享内存函数CreateFileMapping()详解

    测试创建和打开文件映射的时候老是得到"句柄无效"的错误, 仔细看了MSDN以后才发觉是函数认识不透, 这里把相关的解释翻译出来 HANDLE CreateFileMapping( ...

  4. C++ 共享内存 函数封装

    #pragma once #include <string> #include <wtypes.h> #include <map> using namespace ...

  5. 给PHP开启shmop扩展实现共享内存

    在项目开发中,想要实现PHP多个进程之间共享数据的功能,让客户端连接能够共享一个状态,需要开启共享内存函数shmop.如果预期考虑会遇到这方面需求,那么最好在编译PHP的时候添加--with-shmo ...

  6. Linux POSIX共享内存方法&ipcs &struct shmid_ds

    内容是主进程创建子进程计算斐波那契数列. 其中计算到第几项是有主进程命令行输入. 共享内存段,并且查看了一些信息. 参考操作系统概念第七版 3.10,3.11 关于LINUX C库函数 中的 fpri ...

  7. c#读写共享内存操作函数封装

    原文 c#读写共享内存操作函数封装 c#共享内存操作相对c++共享内存操作来说原理是一样,但是c#会显得有点复杂. 现把昨天封装的读写共享内存封装的函数记录下来,一方面希望给需要这块的有点帮助,另一方 ...

  8. System V 共享内存 和 系列函数

    跟消息队列一样,共享内存也有自己的数据结构,如下: struct shmid_ds { struct ipc_perm shm_perm;    /* Ownership and permission ...

  9. PHP共享内存详解

    前言 在PHP中有这么一族函数,他们是对UNIX的V IPC函数族的包装. 它们很少被人们用到,但是它们却很强大.巧妙的运用它们,可以让你事倍功半. 它们包括: 信号量(Semaphores) 共享内 ...

随机推荐

  1. 【转】JsonPath教程

    https://blog.csdn.net/koflance/article/details/63262484 1. 介绍 类似于XPath在xml文档中的定位,JsonPath表达式通常是用来路径检 ...

  2. 《算法笔记》8.1小节——搜索专题->深度优先搜索(DFS)

    http://codeup.cn/contest.php 5972 这是递归的入门题,求全排列,第一种方法用STL中的函数next_permutation,可以很容易的实现.首先建立好数组,将需要全排 ...

  3. GO linux LiteIDE

    GO 有个IDE开发环境,还是挺不错的 要明确一下,GO主要还是服务器端语言,所以,这里只以linux为例来说明安装和使用 一. 下载https://www.golangtc.com/download ...

  4. RNN通俗理解

    让数据间的关联也被 NN 加以分析,我们人类是怎么分析各种事物的关联,?最基本的方式,就是记住之前发生的事情. 那我们让神经网络也具备这种记住之前发生的事的能力. 再分析 Data0 的时候, 我们把 ...

  5. Mysql重连错误

    Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully rec ...

  6. SQLSetStmtAttr

    SQLSetStmtAttr 函数定义: Stmt是用来执行SQL语句的句柄,这个函数是用来设置她的属性的 SQLRETURN SQLSetStmtAttr( SQLHSTMT     , 这是由游标 ...

  7. html5-常用的3个基本标签

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  8. maven工程的common模块jar上传至仓库并被其它模块依赖

    .parent pom和common pom 都需要添加 <distributionManagement> <repository> <id>nexus</i ...

  9. [protocol]GO enrichment analysis

    [protocol]GO enrichment analysis     背景: 什么是富集分析,自己可以百度.我到目前也没发现一个比较通俗易懂的介绍.直接理解为一种统计学方法就可以了. 用于查看显著 ...

  10. Spring boot FastJson

    介绍:FastJson 是ailibaba 的一款解析Json的开源框架 使用方式1 引入jar 包 <dependency>    <groupId>com.alibaba& ...