⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch16_02.htm

📁 编程珍珠,里面很多好用的代码,大家可以参考学习呵呵,
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html><head><title>Files (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly &amp; Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Files"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch16_01.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch16_01.htm">Chapter 16: Interprocess Communication</a></td><td align="right" valign="top" width="172"><a href="ch16_03.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">16.2. Files</h2><p><a name="INDEX-2951"></a><a name="INDEX-2952"></a>Perhaps you've never thought about files as an IPC mechanism before,but they shoulder the lion's share of interprocess communication--farmore than all other means combined.  When one process deposits itsprecious data in a file and another process later retrieves that data,those processes have communicated.  Files offer something unique amongall forms of IPC covered here: like a papyrus scroll unearthed aftermillennia buried in the desert, a file can be unearthed and readlong after its writer's personal end.<a href="#FOOTNOTE-6">[6]</a>  Factoring in persistencewith comparative ease of use, it's no wonder that files remainpopular.</p><blockquote class="footnote"><a name="FOOTNOTE-6"></a><p>[6] Presuming that a process canhave a personal end.</p></blockquote><p>Using files to transmit information from the dead past to some unknownfuture poses few surprises.  You write the file to some permanentmedium like a disk, and that's about it.  (You might tell a web serverwhere to find it, if it contains HTML.)  The interesting challenge iswhen all parties are still alive and trying to communicate with oneanother.  Without some agreement about whose turn it is to have theirsay, reliable communication is impossible; agreement may be achieved through file locking, which iscovered in the next section.  In the section after that, we discuss thespecial relationship that exists between a parent process and itschildren, which allows related parties to exchange information throughinherited access to the same files.</p><p>Files certainly have their limitations when it comes to things likeremote access, synchronization, reliability, and session management.Other sections of the chapter cover various IPC mechanismsinvented to address such limitations.</p><a name="ch16-sect-fl"></a><h3 class="sect2">16.2.1. File Locking</h3><p><a name="INDEX-2953"></a><a name="INDEX-2954"></a>In a multitasking environment, you need to be careful not to collidewith other processes that are trying to use the same file you're using. As long as all processes are just reading, there's no problem, but as soon aseven one process needs to write to the file, complete chaos ensuesunless some sort of locking mechanism acts as traffic cop.</p><p><a name="INDEX-2955"></a>Never use the mere existence of a filename (that is, <tt class="literal">-e $file</tt>) as alocking indication, because a race condition exists between the testfor existence of that filename and whatever you plan to do with it(like create it, open it, or unlink it).  See the section <a href="ch23_02.htm#ch23-sect-hrc">Section 16.2.2, "Handling Race Conditions"</a> in <a href="ch23_01.htm">Chapter 23, "Security"</a>, for more about this.</p><p><a name="INDEX-2956"></a>Perl's portable locking interface is the <tt class="literal">flock</tt>(<em class="replaceable">HANDLE</em>,<em class="replaceable">FLAGS</em>)function, described in <a href="ch29_01.htm">Chapter 29, "Functions"</a>.  Perl maximizesportability by using only the simplest and most widespread lockingfeatures found on the broadest range of platforms.  These semanticsare simple enough that they can be emulated on most systems, includingthose that don't support the traditional syscall of that name, suchas System V or Windows NT.  (If you're running a Microsoft system earlierthan NT, though, you're probably out of luck, as you would be ifyou're running a system from Apple before Mac OS X.)<a name="INDEX-2957"></a></p><p><a name="INDEX-2958"></a><a name="INDEX-2959"></a><a name="INDEX-2960"></a>Locks come in two varieties: shared (the <tt class="literal">LOCK_SH</tt> flag) and exclusive(the <tt class="literal">LOCK_EX</tt> flag).  Despite the suggestive sound of "exclusive",processes aren't required to obey locks on files.  That is, <tt class="literal">flock</tt>only implements <em class="emphasis">advisory locking</em>, which means that locking a filedoes not stop another process from reading or even writing the file.Requesting an exclusive lock is just a way for a process to let theoperating system suspend it until all current lockers, whether sharedor exclusive, are finished with it.  Similarly, when a process asks fora shared lock, it is just suspending itself until there is no exclusivelocker.  Only when all parties use the file-locking mechanism can acontended file be accessed safely.</p><p><a name="INDEX-2961"></a>Therefore, <tt class="literal">flock</tt> is a blocking operation by default.  That is, if youcan't get the lock you want immediately, the operating system suspendsyour process till you can.  Here's how to get a blocking, shared lock,typically used for reading a file:<blockquote><pre class="programlisting">use Fcntl qw(:DEFAULT :flock);open(FH, "&lt; filename")  or die "can't open filename: $!";flock(FH, LOCK_SH)      or die "can't lock filename: $!";# now read from FH</pre></blockquote>You can try to acquire a lock in a nonblocking fashion by includingthe <tt class="literal">LOCK_NB</tt> flag in the <tt class="literal">flock</tt> request.  If you can't be given thelock right away, the function fails and immediately returns false.Here's an example:<blockquote><pre class="programlisting">flock(FH, LOCK_SH | LOCK_NB)    or die "can't lock filename: $!";</pre></blockquote>You may wish to do something besides raising an exception as we didhere, but you certainly don't dare do any I/O on the file.  If you arerefused a lock, you shouldn't access the file until you can get the lock.Who knows what scrambled state you might find the file in?  The mainpurpose of the nonblocking mode is to let you go off and do somethingelse while you wait.  But it can also be useful for producingfriendlier interactions by warning users that it might takea while to get the lock, so they don't feel abandoned:<blockquote><pre class="programlisting">use Fcntl qw(:DEFAULT :flock);open(FH, "&lt; filename")  or die "can't open filename: $!";unless (flock(FH, LOCK_SH | LOCK_NB)) {    local $| = 1;    print "Waiting for lock on filename...";    flock(FH, LOCK_SH)  or die "can't lock filename: $!";    print "got it.\n"} # now read from FH</pre></blockquote>Some people will be tempted to put that nonblocking lock into a loop.The main problem with nonblocking mode is that, by the time you getback to checking again, someone else may have grabbed the lock becauseyou abandoned your place in line.  Sometimes you just have to get inline and wait.  If you're lucky there will be some magazines to read.</p><p><a name="INDEX-2962"></a><a name="INDEX-2963"></a>Locks are on filehandles, not on filenames.<a href="#FOOTNOTE-7">[7]</a>  When you close the file, the lockdissolves automatically, whether you close the file explicitly bycalling <tt class="literal">close</tt> or implicitly by reopening the handle or by exitingyour process.</p><blockquote class="footnote"><a name="FOOTNOTE-7"></a><p>[7] Actually, locksaren't on filehandles--they're on the file descriptors associated withthe filehandles since the operating system doesn't know aboutfilehandles.  That means that all our <tt class="literal">die</tt> messages about failing toget a lock on filenames are technically inaccurate.  But error messagesof the form "I can't get a lock on the file represented by the filedescriptor associated with the filehandle originally opened to the path<em class="emphasis">filename</em>, although by now <em class="emphasis">filename</em> may represent a different fileentirely than our handle does" would just confuse the user (not tomention the reader).</p></blockquote><p><a name="INDEX-2964"></a>To get an exclusive lock, typically used for writing, you have tobe more careful.  You cannot use a regular <tt class="literal">open</tt> for this; if youuse an open mode of <tt class="literal">&lt;</tt>, it will fail on files that don'texist yet, and if you use <tt class="literal">&gt;</tt>, it will clobber any filesthat do.  Instead, use <tt class="literal">sysopen</tt> on the file so it can be lockedbefore getting overwritten.  Once you've safely opened the file forwriting but haven't yet touched it, successfully acquire the exclusivelock and only <em class="emphasis">then</em> truncate the file.  Now you may overwrite itwith the new data.<blockquote><pre class="programlisting">use Fcntl qw(:DEFAULT :flock);sysopen(FH, "filename", O_WRONLY | O_CREAT)    or die "can't open filename: $!";flock(FH, LOCK_EX)    or die "can't lock filename: $!";truncate(FH, 0)    or die "can't truncate filename: $!";# now write to FH</pre></blockquote><a name="INDEX-2965"></a>If you want to modify the contents of a file in place, use <tt class="literal">sysopen</tt>again.  This time you ask for both read and write access, creatingthe file if needed.  Once the file is opened, but before you'vedone any reading or writing, get the exclusive lock and keep itaround your entire transaction.  It's often best to release the lockby closing the file because that guarantees all buffers are writtenbefore the lock is released.</p><p>An update involves reading in old values and writing out new ones.  Youmust do both operations under a single exclusive lock, lest anotherprocess read the (imminently incorrect) value after (or even before)you do, but before you write.  (We'll revisit this situation when wecover shared memory later in this chapter.)<blockquote><pre class="programlisting">use Fcntl qw(:DEFAULT :flock);sysopen(FH, "counterfile", O_RDWR | O_CREAT)    or die "can't open counterfile: $!";flock(FH, LOCK_EX)    or die "can't write-lock counterfile: $!";$counter = &lt;FH&gt; || 0;  # first time would be undefseek(FH, 0, 0)    or die "can't rewind counterfile : $!";print FH $counter+1, "\n"    or die "can't write counterfile: $!";# next line technically superfluous in this program, but# a good idea in the general casetruncate(FH, tell(FH))    or die "can't truncate counterfile: $!";close(FH)    or die "can't close counterfile: $!";</pre></blockquote><a name="INDEX-2966"></a>You can't lock a file you haven't opened yet, and you can't have asingle lock that applies to more than one file.  What you can do,though, is use a completely separate file to act as a sort ofsemaphore, like a traffic light, to provide controlled access tosomething else through regular shared and exclusive locks on thesemaphore file.  This approach has several advantages.  You can haveone lockfile that controls access to multiple files, avoiding the kindof deadlock that occurs when one process tries to lock those files inone order while another process is trying to lock them in a differentorder.  You can use a semaphore file to lock an entire directory offiles.  You can even control access to something that's not even in thefilesystem, like a shared memory object or the socket upon whichseveral preforked servers would like to call <tt class="literal">accept</tt>.</p><p><a name="INDEX-2967"></a><a name="INDEX-2968"></a>If you have a DBM file that doesn't provide its own explicit lockingmechanism, an auxiliary lockfile is the best way to control concurrent

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -