Question

I'm mostly familiar with Java, C and C++ in which there are ways to control that only one thread is accessing a resource at any given time. Now I'm in search for something similar but in PHP 5.x.

To formulate my problem with one example:

I have an ASCII-file which only stores a number, the value of a page load counter. At application deployment the file will simply hold a 0. For each access the value will be incremented by one. The goal is to keep track of page loads.

The problem comes when many users are concurrently accessing the page containing the counter. When thread A has read the current value, let's say it is 11, another thread which we call B reads the value, still 11. Then the first thread A increments the read value and writes 12 in the file and closes it. Then the second thread B, increments the read value, which was 11, gets 12 and writes that into the file. The value 12 is stored in the file, when it really should have been 13.

In another programming language I would have solved this using a mutex. I understand there are mutexes, shared memory and other funcionality as part of modules. But I would like a solution which works on "most servers" out there. Platform independent. Installed on most cheap web hosts. Is there a good solution to this problem? And if there isn't, which way would you take if using a database is not an option?

Was it helpful?

Solution

You could try php's variant of flock (http://www.php.net/flock)

I would envision something similar to (this assumes that the file /tmp/counter.txt already exists and has a counter in the file):

<?php

$fp = fopen("/tmp/counter.txt", "r+");

echo "Attempt to lock\n";
if (flock($fp, LOCK_EX)) {
  echo "Locked\n";
  // Read current value of the counter and increment
  $cntr = fread($fp, 80);
  $cntr = intval($cntr) + 1;

  // Pause to prove that race condition doesn't exist
  sleep(5);

  // Write new value to the file
  ftruncate($fp, 0);
  fseek($fp, 0, SEEK_SET);
  fwrite($fp, $cntr);
  flock($fp, LOCK_UN); // release the lock
  fclose($fp);
}

?>

OTHER TIPS

PHP's flock() function is the route to go. However, you have to make sure that all accesses to the file are protected by a call to flock() first. PHP won't check if the file is locked unless you explicitly make the call to do so.

The concept is virtually identical as with mutexes (protecting shared resources, et al), but it's important enough to bear special emphasis.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top