Home > Archive > PERL Miscellaneous > November 2005 > FAQ 5.20 Why can't I just open(FH, ">file.lock")?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
FAQ 5.20 Why can't I just open(FH, ">file.lock")?
|
|
| PerlFAQ Server 2005-11-16, 7:01 pm |
| This message is one of several periodic postings to comp.lang.perl.misc
intended to make it easier for perl programmers to find answers to
common questions. The core of this message represents an excerpt
from the documentation provided with Perl.
--------------------------------------------------------------------
5.20: Why can't I just open(FH, ">file.lock")?
A common bit of code NOT TO USE is this:
sleep(3) while -e "file.lock"; # PLEASE DO NOT USE
open(LCK, "> file.lock"); # THIS BROKEN CODE
This is a classic race condition: you take two steps to do something
which must be done in one. That's why computer hardware provides an
atomic test-and-set instruction. In theory, this "ought" to work:
sysopen(FH, "file.lock", O_WRONLY|O_EXCL|O_CREAT)
or die "can't open file.lock: $!";
except that lamentably, file creation (and deletion) is not atomic over
NFS, so this won't work (at least, not every time) over the net. Various
schemes involving link() have been suggested, but these tend to involve
busy-wait, which is also subdesirable.
--------------------------------------------------------------------
Documents such as this have been called "Answers to Frequently
Asked Questions" or FAQ for short. They represent an important
part of the Usenet tradition. They serve to reduce the volume of
redundant traffic on a news group by providing quality answers to
questions that keep coming up.
If you are some how irritated by seeing these postings you are free
to ignore them or add the sender to your killfile. If you find
errors or other problems with these postings please send corrections
or comments to the posting email address or to the maintainers as
directed in the perlfaq manual page.
Note that the FAQ text posted by this server may have been modified
from that distributed in the stable Perl release. It may have been
edited to reflect the additions, changes and corrections provided
by respondents, reviewers, and critics to previous postings of
these FAQ. Complete text of these FAQ are available on request.
The perlfaq manual page contains the following copyright notice.
AUTHOR AND COPYRIGHT
Copyright (c) 1997-2002 Tom Christiansen and Nathan
Torkington, and other contributors as noted. All rights
reserved.
This posting is provided in the hope that it will be useful but
does not represent a commitment or contract of any kind on the part
of the contributers, authors or their agents.
| |
| Purl Gurl 2005-11-16, 9:57 pm |
| PerlFAQ Server wrote:
> 5.20: Why can't I just open(FH, ">file.lock")?
> A common bit of code NOT TO USE is this:
> sleep(3) while -e "file.lock"; # PLEASE DO NOT USE
> open(LCK, "> file.lock"); # THIS BROKEN CODE
After all these years, after dozens of discussions of this, after
highlighting the idiocy of statements above, this FAQ persists
in promulgating wrong information.
This "broken code" routine is old and a pile of smelly mule manure.
I would think after years of pointing to the ignorance of this FAQ,
someone would show some pride and correct this embarrassment.
Semaphore locking is a well accepted method, a highly adaptable
method, and the only method available for some systems.
Purl Gurl
| |
| A. Sinan Unur 2005-11-16, 9:57 pm |
| "Purl Gurl" <purlgurl@purlgurl.net> wrote in news:z9Cdnci8jPOnd-beRVn-
tQ@giganews.com:
> PerlFAQ Server wrote:
>
>
>
>
> After all these years, after dozens of discussions of this, after
> highlighting the idiocy of statements above, this FAQ persists
> in promulgating wrong information.
>
> This "broken code" routine is old and a pile of smelly mule manure.
>
> I would think after years of pointing to the ignorance of this FAQ,
> someone would show some pride and correct this embarrassment.
The code above is indeed broken.
> Semaphore locking is a well accepted method, a highly adaptable
> method, and the only method available for some systems.
And the right way of doing it is explained in the portion of the FAQ
answer which you ignorantly snipped.
Sinan
--
A. Sinan Unur <1usa@llenroc.ude.invalid>
(reverse each component and remove .invalid for email address)
comp.lang.perl.misc guidelines on the WWW:
http://mail.augustmail.com/~tadmc/c...guidelines.html
| |
| Lars Kellogg-Stedman 2005-11-16, 9:57 pm |
| > Semaphore locking is a well accepted method, a highly adaptable
> method, and the only method available for some systems.
Semaphore locking is certainly useful, but there are ways of
implementing it that are less prone to race conditions (for example,
using a "flag directory" instead of a "flag file", since in many cases
directory creation is atomic -- unlike touching a file, which will
happily succeed for multiple processes).
I think the real problem with the FAQ is that while it goes on about how
this won't work in an NFS environment it doesn't actually present or
suggest a working solution.
-- Lars
--
Lars Kellogg-Stedman <8273grkci8q8kgt@jetable.net>
This email address will expire on 2005-11-23.
| |
| Purl Gurl 2005-11-16, 9:57 pm |
| Lars Kellogg-Stedman wrote:
[color=darkred]
> Semaphore locking is certainly useful, but there are ways of
> implementing it that are less prone to race conditions (for example,
> using a "flag directory" instead of a "flag file", since in many cases
> directory creation is atomic -- unlike touching a file, which will
> happily succeed for multiple processes).
> I think the real problem with the FAQ is that while it goes on about how
> this won't work in an NFS environment it doesn't actually present or
> suggest a working solution.
So very true.
All file locks methods have benefits and di vantages. No single
file lock method works perfectly; all involve some risk.
A clear risk with semaphore locking is a program crash before
releasing the lock. This is a risk for which none can offer any
viable solution, short of periodic "garbage collection" of locks.
Even garbage collection is a risk because a file lock might
be legitimate and in use when the garbage man comes around.
Semaphore locking is the _only_ method for some systems.
Yes, this FAQ, like a few others, never addresses its own topic;
no worthwhile information is presented about file locking.
The writer of this FAQ is, in essence, is writing,
"If your system does not support *nix style locking, you are SOL."
This is one of a number of FAQs which really annoy me. Over a
number of years many have pointed to the fallacy of this FAQ,
and yet it remains an embarrassment to the Perl Community.
Purl Gurl
| |
| Purl Gurl 2005-11-16, 9:57 pm |
| Purl Gurl wrote:
> Lars Kellogg-Stedman wrote:
[color=darkred]
Which reminds me.
Your directory method is a little known method. It has been a longtime
since I read comments about employing a directory as a file lock.
My personal reminder is two or three years back I afforded this group
two methods for Win32 file locking, other than semaphore. However,
semaphore is the easiest to implement.
One method of Win32 file locking employs a compiled C binary,
the other is a hack which assigns a read only attribute to allow
reading but not writing. While locked, DOS xcopy can be used
to defeat the read only attribute. When finished, the read only
attribute is removed.
Again, semaphore locking should be the first choice being simple
and efficient. For "mission critical" locking, then a binary or a
secure read only method should be used, for Win32.
I am sitting in front of new XP Pro dual processor machine and
am wondering if extensive XP security could be used as a hack
for yet another way to lock a Win32 file; change the file owner
or turn off file sharing for web applications.
http://www.purlgurl.net/~purlgurl/perl/perl.html
For those interested, about middle of that page for Win32 lock hacks.
Purl Gurl
| |
| Trey Waters 2005-11-17, 6:59 pm |
| On Wed, 16 Nov 2005, Lars Kellogg-Stedman wrote:
>
> Semaphore locking is certainly useful, but there are ways of
> implementing it that are less prone to race conditions (for example,
> using a "flag directory" instead of a "flag file", since in many cases
> directory creation is atomic -- unlike touching a file, which will
> happily succeed for multiple processes).
I think you are misunderstanding the definition of "atomic". "Atomic"
does not imply that once one process does something (ie., creates a flag
file/dir), another process will not be able to. "Atomic", in this
instance, means that the lock check AND the lock creation happen in one,
uninterruptible step.
What creates the race condition in the "broken code" is the fact that the
lock check and the lock creation are NOT atomic...IOW, the occur in 2
steps:
1st step: the while loop exits because the lock file is no longer present
2nd step: lock file created for current process
In this case (assuming 2 processes are waiting to create a lock at the
same time), process A passes Step 1, the CPU interrupts process A to run
process B, process B then passes Step 1. Now both are available to create
lock files, and both processes assume they have sole control over whatever
resource needs protecting by the semaphore.
However, I do agree that using "lock directories" can be more reliable
than "lock files". So, I propose this solution to the "broken code", and
welcome comments:
while (!(mkdir("lock.dir")) { sleep 3 }
Here, the check and lock creation are atomic (my lack of knowledge of
mkdir() notwithstanding), so the race condition should be avoided.
-Trey Waters
+-----------------------------------------------------------------------+
Trey Waters news5@sidestreet.gotdns.org
Experience is the worst teacher.
It always gives the test first and the instruction afterward.
+-----------------------------------------------------------------------+
| |
| Purl Gurl 2005-11-17, 6:59 pm |
| Trey Waters wrote:
> while (!(mkdir("lock.dir")) { sleep 3 }
while (!(mkdir("lock.dir"))) { sleep 3; }
=)
Purl Gurl
| |
| Trey Waters 2005-11-18, 7:00 pm |
| On Thu, 17 Nov 2005, Purl Gurl wrote:
> Trey Waters wrote:
>
>
> while (!(mkdir("lock.dir"))) { sleep 3; }
>
Doh... I'll learn to count one of these days! :)
+-----------------------------------------------------------------------+
Trey Waters news5@sidestreet.gotdns.org
Experience is the worst teacher.
It always gives the test first and the instruction afterward.
+-----------------------------------------------------------------------+
| |
| Purl Gurl 2005-11-18, 7:00 pm |
| Trey Waters wrote:
> Purl Gurl wrote:
[color=darkred]
[color=darkred]
[color=darkred]
> Doh... I'll learn to count one of these days! :)
I would need a million hands to count on my fingers how
many times I have made the same mistake.
Some editors will display various font colors for checking,
other will match braces. Many editors have a lot of fancy
whistles and bells. I don't use those editors.
I use antiquated PFE32 for editing. It is very powerful, full
of features new editors do not have, but does not have all
those annoying whistles and bells.
This format helps me during development,
while ( ! ( mkdir ( "lock.dir" ) ) ) { sleep 3; }
Having spaces in there makes for easier "eyeball" checking.
Eventually, I end with this format,
while (!( mkdir ("lock.dir"))) { sleep 3; }
My preference is to have spaces around commands,
even in my final script version. This makes it easier
to "eyeball" my command sequence for logic flow.
No big deal. We all make those types of mistakes,
over and over and over...
Only time those mistakes are annoying is when an
error message indicates line 4934 and you discover
it is a run-away on line 2 after an hour of checking,
editing and testing.
Purl Gurl
|
|
|
|
|