最近研究liunx 服务器多进程并发发现进程并发之间有很多问题,最主要的就是内容协同,遂做了一个简单的基于liunx信号量实现的表锁的table类拿出来分享一下
namespace Table;
/* 基于表锁的多进程共享内存 */
class Table
{
/* 共享内存句柄 */
protected $shm_resource;
/* 信号量句柄 */
protected $signal;
/**
* Table constructor.
*
* @param int table size
*/
public function __construct($size=1024)
{
/* 生成共享内存句柄 */
$shm_mem=shm_attach(ftok(__FILE__,'a'),$size,0666);
/* 共享内存句柄挂载 */
$this->shm_resource=$shm_mem;
/* 挂载信号量 */
$this->signal=sem_get(ftok(__FILE__,'b'));
}
/**
* 共享内存写入消息
*
* @param int $key
* @param string $value
* @param bool serialize
* @return bool isWriteSuccess
*/
public function writeMem(int $key,string $value,bool $serialize=TRUE)
{
if(sem_acquire($this->signal))
{
/* 写入共享内存数据 */
$writeRes=shm_put_var($this->shm_resource,$key,$serialize?serialize($value):$value);
/* 释放信号量 */
sem_release($this->signal);
return $writeRes;
}
}
/**
* 获取共享内存消息
*
*
* @param int $key
* @param bool $unserialize
* @return string content
*/
public function readMem(int $key,bool $unserialize=TRUE)
{
if(sem_acquire($this->signal))
{
/* 读取共享内存资源 */
$content=shm_get_var($this->shm_resource,$key);
$content=$unserialize?unserialize($content):$content;
/* 释放信号量 */
sem_release($this->signal);
return $content;
}
}
/**
* 原子修改行内容
*
*
* @param int $key
* @param \Closure $func
* @param bool $serialize
* @return bool 写入状态
*/
public function updateMem(int $key,\Closure $func,bool $serialize=TRUE)
{
/* 闭包修改 */
$res=call_user_func($func,$this->readMem($key));
/* 写入共享内存 */
return (bool)$this->writeMem($key,$res);
}
/**
* 删除表中k值
*
*
* @param int $key
* @return bool
*/
public function delMem(int $key)
{
/* 检查是否存在 */
if(!shm_has_var($this->shm_resource,$key))return false;
/* 清除内容 */
if(sem_acquire($this->signal))
{
/* 执行删除 */
$status=(bool)shm_remove_var($this->shm_resource,$key);
/* 释放信号量 */
sem_release($this->signal);
return $status;
}
/* 无任何返回false */
return false;
}
/**
* 析构函数
*/
public function __destruct()
{
// TODO: Implement __destruct() method.
/* 清空信号量句柄 */
sem_remove($this->signal);
/* 清空共享内存 */
shm_detach($this->shm_resource);
}
}
以上的table类实现了基于sem信号自动排队操作表的功能下面给个多进程操作的案例
namespace process
class Process
{
public function getInfo()
{
/* 实例化类 */
$table=new \Table\Table();
$pid=pcntl_fork();
if($pid==0)
{
/* 子进程逻辑 */
/* 共享表写入 */
while(true)
{
echo '子进程等待获取表锁'.PHP_EOL;
$table->writeMem(1,time());
echo '子进程已释放表锁'.PHP_EOL;
sleep(2);
}
}
elseif($pid>0)
{
/* 父进程逻辑 */
/* 父进程读取 */
while (true)
{
echo '父进程获取表锁'.PHP_EOL;
echo $table->readMem(1).PHP_EOL;
echo '父进程释放表锁'.PHP_EOL;
sleep(2);
}
}
}
}
以上就是最简单的基于信号量的表锁table , 后续考虑实现基于行锁的表。
ps: 最后在备注一下,该类实现的读写均有锁,默认所有表的操作均会触发信号量调度。