note 62638 added to function.flock

From: Date: Mon, 06 Mar 2006 05:45:12 +0000
Subject: note 62638 added to function.flock
Groups: php.notes 
Request: Send a blank email to php-notes+get-104879@lists.php.net to get a copy of this message
Re: Niels Jaeckel The code posted unfortunately does NOT work in race conditions, because even though it is improbable, there is still a chance the 'mutex' will fail and you will encounter a situation where two programs have a 'lock' for the same file at the same time. It is improbable, but in a busy system with perhaps many processes trying to open one file or perhaps two processes opening the file several times, the probability rises and you will most certianly get strange bugs at strange times. Even though it looks quite improbable, there are two problems: 1) The extra ifs do not add any extra precautions. You might as well usleep for a few microseconds because only the last one matters. 2) Even though it looks like a single atomic command, if you look at the PHP source code, touch is relatively complicated. It gets the time from the computer, checks the base directory, etc.,etc. This means that there will be times that this lock fails, no matter how improbable. What makes a race condition so nasty is that it happens only once every so often, making it nearly impossible to debug and really annoying. *** The only safe way to implement locks is with flock or some other locking mechanism *outside* of PHP. *** (caveat: there may be an alternate locking mechanism in PHP i don't know about, but you cannot make your own) To put this to rest, make a PHP script using the functions described in the previous post. Then, add this code to the file: <?php /*** test.php ***/ // lock and unlock function defs go here while(1) { if(lock("test")) { $f=fopen("importantfile", "w") or die; $pid=getmypid(); $string="Important Information! From $pid"; fwrite($f, $string); fclose($f); $check=file_get_contents("importantfile"); if($check != $string) { echo "THIS LOCK FAILED!\\n"; } unlock("test"); } } ?> Then run this script from the command line - it will loop forever happily. Then, *while that script is running*, run the same script again while the first one is still going. In a UNIX environment you can do this by typing: > php test.php & > php test.php & You will probably see this: Warning: unlink(test.lock): No such file or directory in lock.php on line 29 THIS LOCK FAILED! Warning: touch(): Utime failed: No such file or directory in lock.php on line 19 a lot of times. This means the lock has failed :) In fact, if you ever think you have invented a clever way to lock a file, test it first in this while loop. Just replace lock and unlock with your function and rearrange the code so it makes sense. Then run it and see if it fails. Note that flock() passes this test beautifully. ---- Server IP: 210.138.109.182 Probable Submitter: 61.195.156.129 ---- X-Spam-Status: No, hits=3.1 required=5.0 tests=DATE_MISSING,FROM_NO_LOWER autolearn=no version=2.64 ---- Manual Page -- http://www.php.net/manual/en/function.flock.php Edit -- http://master.php.net/note/edit/62638 Del: integrated -- http://master.php.net/note/delete/62638/integrated Del: useless -- http://master.php.net/note/delete/62638/useless Del: bad code -- http://master.php.net/note/delete/62638/bad+code Del: spam -- http://master.php.net/note/delete/62638/spam Del: non-english -- http://master.php.net/note/delete/62638/non-english Del: in docs -- http://master.php.net/note/delete/62638/in+docs Del: other reasons-- http://master.php.net/note/delete/62638 Reject -- http://master.php.net/note/reject/62638 Search -- http://master.php.net/manage/user-notes.php

« previous php.notes (#104879) next »