使用共享内存实现php Spinlock
时间:2011-07-17
来源:互联网
本文使用共享内存方式实现一个属于php的“自旋锁(Spinlock)”。
主要特点:
1、检测和避免死锁
2、并可以自定义锁定超时
3、可以在运行结束后自动释放锁定
4、可搜集分析锁竞争和锁等待情况
在两个浏览器打开运行这个代码,分别输出,
浏览器1:
Start:13:07:19,Stop:13:07:22
浏览器2:
Start:13:07:19,Stop:13:07:25
第一个浏览器显示程序运行了3秒后结束。
第二个浏览器等待3秒后开始运行,总共耗时6秒,测试通过。
主要特点:
1、检测和避免死锁
2、并可以自定义锁定超时
3、可以在运行结束后自动释放锁定
4、可搜集分析锁竞争和锁等待情况
复制内容到剪贴板
<?php
/**
* php"自旋锁"功能 (PHP Spinlocks)
* 用于php进程同步时使用
*
* Author : lajabs.net 2011/7/15
*/
class slock
{
/**
* $lock_timeout 设置等待回旋次数
* $lock_wait_func 设置等待机制,本例使用usleep+mt_rand随机等待,随机等待有利错开多个竞争
* $add_func 这里设置添加锁标志机制,本例使用PHP的APC组件apc_add函数,apc_add设定锁占有上限为5s,避免永久占有
* $del_func 这里设置删除锁标志机制,本例使用PHP的APC组件apc_delete函数
*/
private $locks;
private $lock_timeout = 200;
private $lock_wait_func;
private $add_func;
private $del_func;
public function __construct()
{
$this->add_func = function($mutex)
{
return apc_add('sl:'.$mutex,1,5);
};
$this->del_func = function($mutex)
{
return apc_delete('sl:'.$mutex);
};
$this->lock_wait_func = function()
{
usleep(mt_rand(10000,50000));
};
}
public function __destruct()
{
$this->clean();
}
/*================================= 分割线 ==========================*/
/**
* 清除当前所有设置的锁,在当前的php进程中可以设置多个锁
*/
public function clean()
{
if($this->locks)
{
foreach($this->locks as $lock => $tmp)
call_user_func($this->del_func ,$lock);
$this->locks = null;
}
}
/**
* 新建立一个锁
* 首先会判断锁定标志是否已经定义,如果已锁定则判定为死锁
* 其次使用apc共享内存方式add一个锁标志,如果失败则进入等待时间,直到超时
*/
public function lock($mutex)
{
if($this->locks[$mutex]!=null)
{
throw new Exception('Detected deadlock.');
return false;
}
while(call_user_func($this->add_func ,$mutex) == false)
{
++$i;
if($i > $this->lock_timeout)
{
throw new Exception('lock timeout.');
return false;
}
call_user_func($this->lock_wait_func);
}
$this->locks[$mutex] = 1;
return $mutex;
}
/**
* 手动释放锁,一般不用,
* 在当前对象析构时会自动释放所有锁
*/
public function release($mutex)
{
if($mutex == false) return false;
unset($this->locks[$mutex]);
call_user_func($this->del_func ,$mutex);
return true;
}
}
/*
Example:
$lock = new slock();
echo 'Start:',date('H:m:s'),',';
$lock->lock(123);
sleep(3);
echo 'Stop:',date('H:m:s');
//$lock->release(123);
*/
?>
运行上述例子,测试同步情况:代码:
<?php
/**
* php"自旋锁"功能 (PHP Spinlocks)
* 用于php进程同步时使用
*
* Author : lajabs.net 2011/7/15
*/
class slock
{
/**
* $lock_timeout 设置等待回旋次数
* $lock_wait_func 设置等待机制,本例使用usleep+mt_rand随机等待,随机等待有利错开多个竞争
* $add_func 这里设置添加锁标志机制,本例使用PHP的APC组件apc_add函数,apc_add设定锁占有上限为5s,避免永久占有
* $del_func 这里设置删除锁标志机制,本例使用PHP的APC组件apc_delete函数
*/
private $locks;
private $lock_timeout = 200;
private $lock_wait_func;
private $add_func;
private $del_func;
public function __construct()
{
$this->add_func = function($mutex)
{
return apc_add('sl:'.$mutex,1,5);
};
$this->del_func = function($mutex)
{
return apc_delete('sl:'.$mutex);
};
$this->lock_wait_func = function()
{
usleep(mt_rand(10000,50000));
};
}
public function __destruct()
{
$this->clean();
}
/*================================= 分割线 ==========================*/
/**
* 清除当前所有设置的锁,在当前的php进程中可以设置多个锁
*/
public function clean()
{
if($this->locks)
{
foreach($this->locks as $lock => $tmp)
call_user_func($this->del_func ,$lock);
$this->locks = null;
}
}
/**
* 新建立一个锁
* 首先会判断锁定标志是否已经定义,如果已锁定则判定为死锁
* 其次使用apc共享内存方式add一个锁标志,如果失败则进入等待时间,直到超时
*/
public function lock($mutex)
{
if($this->locks[$mutex]!=null)
{
throw new Exception('Detected deadlock.');
return false;
}
while(call_user_func($this->add_func ,$mutex) == false)
{
++$i;
if($i > $this->lock_timeout)
{
throw new Exception('lock timeout.');
return false;
}
call_user_func($this->lock_wait_func);
}
$this->locks[$mutex] = 1;
return $mutex;
}
/**
* 手动释放锁,一般不用,
* 在当前对象析构时会自动释放所有锁
*/
public function release($mutex)
{
if($mutex == false) return false;
unset($this->locks[$mutex]);
call_user_func($this->del_func ,$mutex);
return true;
}
}
/*
Example:
$lock = new slock();
echo 'Start:',date('H:m:s'),',';
$lock->lock(123);
sleep(3);
echo 'Stop:',date('H:m:s');
//$lock->release(123);
*/
?>
在两个浏览器打开运行这个代码,分别输出,
浏览器1:
Start:13:07:19,Stop:13:07:22
浏览器2:
Start:13:07:19,Stop:13:07:25
第一个浏览器显示程序运行了3秒后结束。
第二个浏览器等待3秒后开始运行,总共耗时6秒,测试通过。
作者: 693696817 发布时间: 2011-07-17
哈哈,又沙发,谢谢啦~!
作者: yjqwyc 发布时间: 2011-07-17
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28