I\'m trying to update a variable in APC, and will be many processes trying to do that.
APC doesn\'t provide locking functionality, so I\'m considering using other me
I realize this is a year old, but I just stumbled upon the question while doing some research myself on locking in PHP.
It occurs to me that a solution might be possible using APC itself. Call me crazy, but this might be a workable approach:
function acquire_lock($key, $expire=60) {
if (is_locked($key)) {
return null;
}
return apc_store($key, true, $expire);
}
function release_lock($key) {
if (!is_locked($key)) {
return null;
}
return apc_delete($key);
}
function is_locked($key) {
return apc_fetch($key);
}
// example use
if (acquire_lock("foo")) {
do_something_that_requires_a_lock();
release_lock("foo");
}
In practice I might throw another function in there to generate a key to use here, just to prevent collision with an existing APC key, e.g.:
function key_for_lock($str) {
return md5($str."locked");
}
The $expire
parameter is a nice feature of APC to use, since it prevents your lock from being held forever if your script dies or something like that.
Hopefully this answer is helpful for anyone else who stumbles here a year later.
APC is now considered unmaintained and dead. It's successor APCu offers locking via apcu_entry. But be aware, that it also prohibits the concurrent execution of any other APCu functions. Depending on your use case, this might be OK for you.
From the manual:
Note: When control enters
apcu_entry()
the lock for the cache is acquired exclusively, it is released when control leavesapcu_entry()
: In effect, this turns the body ofgenerator
into a critical section, disallowing two processes from executing the same code paths concurrently. In addition, it prohibits the concurrent execution of any other APCu functions, since they will acquire the same lock.
If the point of the lock is to prevent multiple processes from trying to populate an empty cache key, why wouldn't you want to have a blocking lock?
$value = apc_fetch($KEY);
if ($value === FALSE) {
shm_acquire($SEMAPHORE);
$recheck_value = apc_fetch($KEY);
if ($recheck_value !== FALSE) {
$new_value = expensive_operation();
apc_store($KEY, $new_value);
$value = $new_value;
} else {
$value = $recheck_value;
}
shm_release($SEMAPHORE);
}
If the cache is good, you just roll with it. If there's nothing in the cache, you get a lock. Once you have the lock, you'll need to double-check the cache to make sure that, while you were waiting to get the lock, the cache wasn't repopulated. If the cache was repopulated, use that value & release the lock, otherwise, you do the computation, populate the cache & then release your lock.
Actually, check to see if this will work better then Peter's suggestion.
http://us2.php.net/flock
use an exclusive lock and if your comfortable with it, put everything else that attempted to lock the file in a 2-3 second sleep. If done right your site will experience a hang regarding the locked resource but not a horde of scripts fighting to cache the samething.