note 74391 added to function.flock
| From: | LemonJuice at osu1 dot php dot net | Date: | Mon, 09 Apr 2007 19:37:40 +0000 |
| Subject: | note 74391 added to function.flock | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-125240@lists.php.net to get a copy of this message | ||
Hi,
The discussions below address flock() in the context of managing integrity of file contents as well
as the context of using flock() in combination with a dummy file to generally establish agreement on
the access state of some other object. The following addresses the latter.
I use this as a replacement for LOCK TABLES because during some transactional update statements I
require the contents of other tables to freeze and transactions and tablelocks don't mix in
mySQL / InnoDB.
<?php
class ReadWriteLock
{
const LOCK_PATH = "locks";
public static function Aquire($ID, $LockType = LOCK_SH, $WouldBlock = TRUE)
{
// Make sure the file exists and we have it opened.
// We don't care about writing to the file. We just need a file reference that flock()
can work on.
// Also, on an OS level all thread's are sharing this file. We don't do access
control in relation to this file.
// So let's assume first that it already exists.
$FileName = self::LOCK_PATH."/lock_$ID.lck";
if(($Resource = @fopen($FileName, "r")) === FALSE)
// Ok, so this is the first time a thread acquires a lock to this $ID. Let's create
the file.
if(($Resource = @fopen($FileName, "w")) === FALSE)
{
// Ok, perhaps some thread created it between the two ifs. This class does not
delete the file so it should now be there.
if(($Resource = @fopen($FileName, "r")) === FALSE)
return FALSE;
}
else
{
// #REF 1
// Ok, it exists now. Just for solidarity and prevention of whatever OS hickups we
can possibly have
// I want this thread to open it in r mode too.
if(fclose($Resource) === FALSE)
return FALSE;
if(($Resource = @fopen($FileName, "r")) === FALSE)
return FALSE;
}
// And this is really where the locking takes place.
if(flock($Resource, $LockType, $WouldBlock)) return $Resource;
fclose($Resource);
return FALSE;
}
public static function Release($Resource)
{
if(fclose($Resource)) return TRUE;
return FALSE;
}
}
// Entering critical section
if(($Lock = ReadWriteLock::Acquire("metadata")) === FALSE)
die("Failed to either create or acquire the lock.")
// Construct SQL statements from meta tables
// Execute constructed SQL statements agains data tables
// Leaving critical section
if((ReadWriteLock::Release($Lock)) === FALSE)
die("Failed to release the lock.");
?>
A few notes about this:
- As you can see, this just creates 'a' file to use as a reference for flock() to work on.
My assumption here is that the operating system uses semaphores internally to implement Flock(). Of
that, I am not sure however and I would appreciate any validation from an expert.
- The problem of the existence of the lockfile is solved by simply not deleting them. Given that
they are all 0-byte files in a specified folder and that they are only of a limited amount makes it
something that works for my solution. Alternatively you could touch() the lockfile upon a succesful
flock() and use a cron job to delete any files that have not been touched since, say, a day (or at
least for the duration of the session timeout setting of your webserver). That would introduce a
race condition for access on the actual file though which I prefer to exclude from the above.
- flock() implements a low priority exclusive lock. This means that once the resource is locked in a
shared mode, exclusive locks may be delayed indefinately if (and only if) a continuous abundance of
shared lock requests come in so that every thread releases his shared lock after another thread has
already gained shared access. For me, this is an ussue and I would appreciate any references to
establish a high priority exclusive lock.
Good luck,
Juice
...Tastes like more!
----
Server IP: 83.137.20.120
Probable Submitter: 85.144.164.25
----
Manual Page -- http://www.php.net/manual/en/function.flock.php
Edit -- https://master.php.net/note/edit/74391
Del: integrated -- https://master.php.net/note/delete/74391/integrated
Del: useless -- https://master.php.net/note/delete/74391/useless
Del: bad code -- https://master.php.net/note/delete/74391/bad+code
Del: spam -- https://master.php.net/note/delete/74391/spam
Del: non-english -- https://master.php.net/note/delete/74391/non-english
Del: in docs -- https://master.php.net/note/delete/74391/in+docs
Del: other reasons-- https://master.php.net/note/delete/74391
Reject -- https://master.php.net/note/reject/74391
Search -- https://master.php.net/manage/user-notes.php