PHP文件编写中的竞争条件

PHP文件编写中的竞争条件,php,concurrency,race-condition,Php,Concurrency,Race Condition,因此,我有一个脚本,用于接受和处理来自其他脚本和/或应用程序的请求。但是,我的脚本必须完成的任务之一是为每个请求分配一个唯一的、连续的“ID” 例如,假设应用程序A向我的脚本发出1000个请求,同时,应用程序B向我的脚本发出500个请求。我必须给他们1500个唯一的序列号,比如2001~3500 但是,它们之间的顺序并不重要,因此我可以给它们这样的数字: #2001 for 1st request from A (henceforth, A1) #2002 for A2 #2003 for B1

因此,我有一个脚本,用于接受和处理来自其他脚本和/或应用程序的请求。但是,我的脚本必须完成的任务之一是为每个请求分配一个唯一的、连续的“ID”

例如,假设应用程序A向我的脚本发出1000个请求,同时,应用程序B向我的脚本发出500个请求。我必须给他们1500个唯一的序列号,比如2001~3500

但是,它们之间的顺序并不重要,因此我可以给它们这样的数字:

#2001 for 1st request from A (henceforth, A1)
#2002 for A2
#2003 for B1
#2004 for A3
#2005 for B2
...and so on...
private function get_last_id()
{
    // Check if lock file exists...
    while (file_exists("LAST_ID_LOCKED")) {
        // Wait a little bit before checking again
        usleep(1000);
    }

    // Create the lock file
    touch("LAST_ID_LOCKED");

    // Create the ID file for the first time if required
    if (!file_exists("LAST_ID_INDICATOR")) {
        file_put_contents("LAST_ID_INDICATOR", 0);
    }

    // Get the last ID
    $last_id = file_get_contents("LAST_ID_INDICATOR");
    // Update the last ID
    file_put_contents("LAST_ID_INDICATOR", $last_id + 1);

    // Delete the lock file
    unlink("LAST_ID_LOCKED");

    return $last_id;
}
我尝试创建一个存储该号码的文件和一个单独的锁文件,其功能如下:

#2001 for 1st request from A (henceforth, A1)
#2002 for A2
#2003 for B1
#2004 for A3
#2005 for B2
...and so on...
private function get_last_id()
{
    // Check if lock file exists...
    while (file_exists("LAST_ID_LOCKED")) {
        // Wait a little bit before checking again
        usleep(1000);
    }

    // Create the lock file
    touch("LAST_ID_LOCKED");

    // Create the ID file for the first time if required
    if (!file_exists("LAST_ID_INDICATOR")) {
        file_put_contents("LAST_ID_INDICATOR", 0);
    }

    // Get the last ID
    $last_id = file_get_contents("LAST_ID_INDICATOR");
    // Update the last ID
    file_put_contents("LAST_ID_INDICATOR", $last_id + 1);

    // Delete the lock file
    unlink("LAST_ID_LOCKED");

    return $last_id;
}
然而,此代码将创建一个竞争条件,如果我向他们发送1500个请求,最后一个ID将有相当多的丢失(例如,仅达到3211个,而不是3500个)

我也尝试过这样使用flock,但没有效果:

private function get_last_id()
{
    $f = fopen("LAST_ID_INDICATOR", "rw");

    while (true) {
        if (flock($f, LOCK_SH)) {
            $last_id = fread($f, 8192);
            flock($f, LOCK_UN);
            fclose($f);
            break;
        }
        usleep($this->config["waiting_time"]);
    }

    $f = fopen("LAST_ID_INDICATOR", "rw");

    while (true) {
        if (flock($f, LOCK_SH)) {
            $last_id = fread($f, 8192);
            $last_id++;
            ftruncate($f, 0);
            fwrite($f, $last_id);
            flock($f, LOCK_UN);
            fclose($f);
            break;
        }
        usleep($this->config["waiting_time"]);
    }

    return $last_id;
}
那么,我还能做些什么来寻找这种情况的解决方案呢


注意:由于服务器的限制,我只能使用PHP5.2,没有信号量之类的东西。

由于似乎没有人给出答案,我会给你一个可能的解决方案

使用作为解决方案的一部分

编辑:如果您不需要保留顺序,则过滤器锁定的效果会更好

显然,这在实现上会有它自己的挑战,但值得一试,如果你做对了,它可能只是为你想做的事做了一件事

既然你提到了信号量,我想你知道足够的知识来理解这个概念


这可以在“.”的第2章中找到。

如果您可以访问具有锁定功能的数据库,则可以使用该数据库。例如,对于具有骨架PHP代码的MySQL:

  • 创建一个具有一行一列的表(如果不希望“双重使用”现有表):

    $sql='CREATE TABLE
    TABLENAME
    (COLUMNNAME INTEGER)ENGINE=MyISAM'

    excecuteSql($sql)

  • 创建一个PHP函数(重新)设置计数器/Id值:

    $sql='UPDATE
    TABLENAME
    SET
    COLUMNNAME
    =0'

    executeSql($sql)

  • 创建一个PHP函数以获取唯一的连续id:

    $sql=“选择获取锁('numberLock',10)”

    executeSql($sql)

    $sql='SELECT*FROM
    TABLENAME
    '

    if($result=mysqli_查询($link,$sql)){

    }

    $sql='UPDATE
    TABLENAME
    SET
    COLUMNNAME
    =
    COLUMNNAME
    +1'

    executeSql($sql)

    $sql=“选择释放锁('numberLock')”

    executeSql($sql)


  • 您可以使用
    uniqid()
    函数生成id,它基于微时间。文件的用途是什么?Uniqid不会这样做,因为它是随机的,我需要数字是连续的。LAST_ID_指示符的用途只是存储最后(最大)的ID号。
    uniqid()
    并非完全随机,虽然不是顺序的,但每次调用函数都会以升序生成ID。使用
    hexdec()
    将其转换为十进制以了解我的意思。是的,这与我的问题非常接近,谢谢。现在主要的问题是如何在PHP中实现它…这是一个复杂的部分,您需要阅读更多关于上面2个锁的内容,创建这样的锁将非常复杂,没有人会在上面发布代码。