在 php 中使用基于文件的计数器时如何防止竞争条件?

How can I prevent a race condition when using a file based counter in php?

我有一个小网页,它根据计数器的 %3(模 3)向用户提供不同的内容。使用 php 从文件中读入计数器,此时计数器递增并写回文件覆盖旧值。 我正在努力使有问题的内容均匀分布,这就是我这样做的原因。

我担心如果两个用户同时访问该页面,那么他们可能会得到相同的数据,或者一个可能无法增加计数器,因为另一个当前正在写入文件。

我是 web-dev 的新手,所以我不确定如何在没有互斥锁的情况下解决这个问题。我考虑过只有一个打开和关闭并在其中执行所有操作,但我试图尽量减少用户无法访问文件的时间。 (因此为什么读写分开打开)

实现某种互斥的最佳方法是什么,以便一次只有一个人访问该文件,并在多个重叠的文件请求进入时创建一个访问队列?主要目标是保持向用户显示的内容的比例,这涉及保持计数器一致。

代码如下:

<?php

  session_start();
  $counterName = "<path/to/file>";
   
  $file = fopen($counterName, "r");
  $currCount = fread($file, filesize($counterName));
  fclose($file);

  $newCount = $currCount + 1;
  $file = fopen($counterName,'w');
  if(fwrite($file, $newCount) === FALSE){
    echo "Could not write to the file";
  }
  fclose($file);

?>

以防万一有人遇到同样的问题,我可以通过添加来解决问题 flock($fp, LOCK_EX | LOCK_NB) 在根据 php 的 flock 函数的文档写入文件之前。我读过它不是最可靠的,但对于我正在做的事情来说已经足够了。 为方便起见,此处提供文档。 https://www.php.net/manual/en/function.flock.php