我想在虚拟命名资源的PHP请求之间实现快速有效的序列化机制,这些机制在脚本完成时会解锁,无论是正常还是由于错误。我以前有eaccelerator_lock()及其对应的eaccelerator_unlock(),但eaccelerator不再实现该功能。我想做的是:
lock_function("my-named-resource");
..
my_might_abort_abruptly_function();
..
unlock_function("my-named-resource");
调用具有完全相同参数的lock_function()的其他PHP脚本应该阻塞,直到此脚本调用unlock_function()或中止。资源名称在处理之前是未知的(它是生成的字符串)并且不能被约束为小集合(即,锁定机制应该具有良好的粒度)。我想避免使用try / catch代码,因为有些环境不会调用catch。此外,应避免使用任何依赖于手动usleep()旋转(而不是本机OS阻塞)的机制。
Mine是服务器中唯一正在运行的应用程序。该系统是带有PHP 5.3.3,Apache 2.2.15的CentOS 6 Linux,我可以完全控制它。
我探索了以下替代方案:
信号量:它们在PHP中实现得不是很好; Linux允许数千个数组,而PHP只为每个id分配一个。
flock():我的资源是虚拟的,而flock()只能锁定整个/真实/现有文件;我需要预先创建数千个文件,然后选择一个用哈希函数锁定。粒度取决于文件的数量。
dio_fcntl():我可以尝试用单个文件和fcntl(F_SETLK)重现flock()的想法。这样可以获得良好的粒度,而不需要很多文件;该文件甚至可以是零字节长! (F_SETLK可以锁定超出文件的末尾)。唉!问题是文档中没有任何地方说过,当脚本终止时,dio_fcntl()会释放资源。
数据库锁:我可以在具有良好密钥锁定粒度的数据库中实现一些密钥锁定,尽管这太依赖于数据库。它也不会那么快。
实现我自己的PHP扩展:我真的想避开这条路。
问题是,我认为某个人应该在我面前考虑过这个问题。什么是好的选择?还有其他我没有看到的解决方案吗?
提前致谢。吉列尔莫。
答案 0 :(得分:0)
答案 1 :(得分:0)
事实证明,在脚本终止时,dio_open()会释放资源。所以我结束了以下功能:
$lockfile = $writable_dir."/serialized.lock";
function serialize_access($name)
{
$f = serialize_openfile();
if( !$f ) return false;
$h = serialize_gethash($name);
return dio_fcntl($f, F_SETLKW, array("whence"=>SEEK_SET,"start"=>$h, "length"=>1, "type"=>F_WRLCK)) >= 0;
}
function serialize_release($name)
{
$f = serialize_openfile();
if( !$f ) return false;
$h = serialize_gethash($name);
@dio_fcntl($f, F_SETLK, array("whence"=>SEEK_SET,"start"=>$h, "length"=>1, "type"=>F_UNLCK));
}
function serialize_gethash($name)
{
// Very good granularity (2^31)
return crc32($name) & 0x7fffffff;
}
function serialize_openfile()
{
global $lockfile, $serialize_file;
if( !isset($serialize_file) )
{
$serialize_file = false;
if( extension_loaded("dio") )
{
$serialize_file = @dio_open($lockfile,O_RDWR);
if( $serialize_file )
{
// Do not attempt to create the file with dio_open()
// because the file permissions get all mangled.
$prev = umask(0);
$temp = fopen($lockfile,"a");
if( $temp )
{
$serialize_file = @dio_open($lockfile,O_RDWR);
fclose($temp);
}
umask($prev);
}
}
}
return $serialize_file;
}
它似乎运作良好。
答案 2 :(得分:0)
实现我自己的PHP扩展
您可能想要检查ninja-mutex库,它完全符合您的要求