具有自动释放功能的PHP虚拟资源访问序列化

时间:2013-06-11 03:02:57

标签: php locking

我想在虚拟命名资源的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扩展:我真的想避开这条路。

问题是,我认为某个人应该在我面前考虑过这个问题。什么是好的选择?还有其他我没有看到的解决方案吗?

提前致谢。吉列尔莫。

3 个答案:

答案 0 :(得分:0)

您的脚本启动时可以随时上学和touch文件,完成后将其删除。

您可以register_shutdown_function删除该文件。

文件的存在与否将指示资源的锁定状态。

答案 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库,它完全符合您的要求