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

📄 ch16_02.htm

📁 编程珍珠,里面很多好用的代码,大家可以参考学习呵呵,
💻 HTM
📖 第 1 页 / 共 2 页
字号:
access by multiple agents.  Otherwise, your DBM library's internalcaching can get out of sync with the file on disk.  Before calling<tt class="literal">dbmopen</tt> or <tt class="literal">tie</tt>, open and lock the semaphore file.  If youopen the database with <tt class="literal">O_RDONLY</tt>, you'll want to use <tt class="literal">LOCK_SH</tt>for the lock.  Otherwise, use <tt class="literal">LOCK_EX</tt> for exclusive accessto updating the database.  (Again, this only works if all participants agree to pay attention to the semaphore.)<blockquote><pre class="programlisting">use Fcntl qw(:DEFAULT :flock);use DB_File;  # demo purposes only; any db is fine$DBNAME  = "/path/to/database";$LCK     = $DBNAME . ".lockfile";# use O_RDWR if you expect to put data in the lockfilesysopen(DBLOCK, $LCK, O_RDONLY | O_CREAT)       or die "can't open $LCK: $!";# must get lock before opening databaseflock(DBLOCK, LOCK_SH)    or die "can't LOCK_SH $LCK: $!";tie(%hash, "DB_File", $DBNAME, O_RDWR | O_CREAT)    or die "can't tie $DBNAME: $!";</pre></blockquote>Now you can safely do whatever you'd like with the tied <tt class="literal">%hash</tt>.When you're done with your database, make sure you explicitlyrelease those resources, and in the opposite order that you acquired them:<blockquote><pre class="programlisting">untie %hash;    # must close database before lockfileclose DBLOCK;   # safe to let go of lock now</pre></blockquote><a name="INDEX-2969"></a>If you have the GNU DBM library installed, you can use the standard<tt class="literal">GDBM_File</tt> module's implicit locking.  Unless the initial <tt class="literal">tie</tt>contains the <tt class="literal">GDBM_NOLOCK</tt> flag, the library makes sure that onlyone writer may open a GDBM file at a time, and that readers and writersdo not have the database open at the same time.</p><h3 class="sect2">16.2.2. Passing Filehandles </h3><p><a name="INDEX-2970"></a><a name="INDEX-2971"></a><a name="INDEX-2972"></a>Whenever you create a child process using <tt class="literal">fork</tt>, that new processinherits all its parent's open filehandles.  Using filehandles forinterprocess communication is easiest to illustrate by using plainfiles first.  Understanding how this works is essential for masteringthe fancier mechanisms of pipes and sockets described later in thischapter.</p><p>The simplest example opens a file and starts up a child process.The child then uses the filehandle already opened for it:<blockquote><pre class="programlisting">open(INPUT, "&lt; /etc/motd")      or die "/etc/motd: $!";if ($pid = fork) { waitpid($pid,0) } else {    defined($pid)         or die "fork: $!";    while (&lt;INPUT&gt;) { print "$.: $_" }    exit;  # don't let child fall back into main code} # INPUT handle now at EOF in parent</pre></blockquote>Once access to a file has been granted by <tt class="literal">open</tt>, it stays granted untilthe filehandle is closed; changes to thefile's permissions or to the owner's access privileges have no effecton accessibility.  Even if the process later alters its user or groupIDs, or the file has its ownership changed to a differentuser or group, that doesn't affect filehandles that are already open.Programs running under increased permissions (like set-id programsor systems daemons) often open a file under their increased rightsand then hand off the filehandle to a child process that could nothave opened the file on its own.</p><p><a name="INDEX-2973"></a><a name="INDEX-2974"></a><a name="INDEX-2975"></a>Although this feature is of great convenience when used intentionally,it can also create security issues if filehandles accidentally leakfrom one program to the next.  To avoid granting implicitaccess to all possible filehandles, Perl automatically closes anyfilehandles it has opened (including pipes and sockets) whenever youexplicitly <tt class="literal">exec</tt> a new program or implicitly execute one through acall to a piped <tt class="literal">open</tt>, <tt class="literal">system</tt>, or <tt class="literal">qx//</tt> (backticks).  The systemfilehandles <tt class="literal">STDIN</tt>, <tt class="literal">STDOUT</tt>, and <tt class="literal">STDERR</tt> are exempt from thisbecause their main purpose is to provide communications linkage betweenprograms.  So one way of passing a filehandle to a new program is tocopy the filehandle to one of the standard filehandles:<blockquote><pre class="programlisting">open(INPUT, "&lt; /etc/motd")      or die "/etc/motd: $!";if ($pid = fork) { wait } else {    defined($pid)               or die "fork: $!";    open(STDIN, "&lt;&amp;INPUT")      or die "dup: $!";    exec("cat", "-n")           or die "exec cat: $!";}</pre></blockquote><a name="INDEX-2976"></a>If you really want the new program to gain access to a filehandleother than these three, you can, but you have to do one of two things.When Perl opens a new file (or pipe or socket), it checks the currentsetting of the <tt class="literal">$^F</tt>(<tt class="literal">$SYSTEM_FD_MAX</tt>) variable.  If the numeric filedescriptor used by that new filehandle is greater than<tt class="literal">$^F</tt>, the descriptor is marked as one to close.Otherwise, Perl leaves it alone, and new programs you<tt class="literal">exec</tt> will inherit access.</p><p><a name="INDEX-2977"></a>It's not always easy to predict what file descriptor your newly openedfilehandle will have, but you can temporarily set your maximum systemfile descriptor to some outrageously high number for the duration ofthe <tt class="literal">open</tt>:<blockquote><pre class="programlisting"># open file and mark INPUT to be left open across execs{     local $^F = 10_000;    open(INPUT, "&lt; /etc/motd")   or die "/etc/motd: $!";} # old value of $^F restored on scope exit</pre></blockquote>Now all you have to do is get the new program to pay attention tothe descriptor number of the filehandle you just opened.  Thecleanest solution (on systems that support this) is to pass aspecial filename that equates to a file descriptor.  If your systemhas a directory called <em class="emphasis">/dev/fd</em> or <em class="emphasis">/proc/$$/fd</em> containing filesnumbered from 0 through the maximum number of supported descriptors,you can probably use this strategy.  (Many Linux operating systemshave both, but only the <em class="emphasis">/proc</em> version tends to be correctlypopulated.  BSD and Solaris prefer <em class="emphasis">/dev/fd</em>.  You'll have to pokearound at your system to see which looks better for you.)  First,open and mark your filehandle as one to be left open across <tt class="literal">exec</tt>sas shown in the previous code, then fork like this:<blockquote><pre class="programlisting">if ($pid = fork) { wait } else {    defined($pid)                or die "fork: $!";    $fdfile = "/dev/fd/" . fileno(INPUT);    exec("cat", "-n", $fdfile)   or die "exec cat: $!";}</pre></blockquote><a name="INDEX-2978"></a>If your system supports the <tt class="literal">fcntl</tt> syscall, you maydiddle the filehandle's close-on-exec flag manually.  This isconvenient for those times when you didn't realize back when youcreated the filehandle that you would want to share it with yourchildren.<blockquote><pre class="programlisting">use Fcntl qw/F_SETFD/;fcntl(INPUT, F_SETFD, 0)    or die "Can't clear close-on-exec flag on INPUT: $!\n";</pre></blockquote>You can also force a filehandle to close:<blockquote><pre class="programlisting">fcntl(INPUT, F_SETFD, 1)    or die "Can't set close-on-exec flag on INPUT: $!\n";</pre></blockquote>You can also query the current status:<blockquote><pre class="programlisting">use Fcntl qw/F_SETFD F_GETFD/;printf("INPUT will be %s across execs\n",    fcntl(INPUT, F_GETFD, 1) ? "closed" : "left open");</pre></blockquote>If your system doesn't support file descriptors named in thefilesystem, and you want to pass a filehandle other than<tt class="literal">STDIN</tt>, <tt class="literal">STDOUT</tt>, or<tt class="literal">STDERR</tt>, you can still do so, but you'll have tomake special arrangements with that program.  Common strategies forthis are to pass the descriptor number through an environment variableor a command-line option.<a name="INDEX-2979"></a></p><p><a name="INDEX-2980"></a>If the executed program is in Perl,you can use <tt class="literal">open</tt> to convert a file descriptor intoa filehandle.  Instead of specifying a filename, use "<tt class="literal">&amp;=</tt>" followed by the descriptor number.  <blockquote><pre class="programlisting">if (defined($ENV{input_fdno}) &amp;&amp; $ENV{input_fdno}) =~ /^\d$/) {     open(INPUT, "&lt;&amp;=$ENV{input_fdno}")        or die "can't fdopen $ENV{input_fdno} for input: $!";}</pre></blockquote>It gets even easier than that if you're going to be runninga Perl subroutine or program that expects a filename argument.  Youcan use the descriptor-opening feature of Perl's regular <tt class="literal">open</tt>function (but not <tt class="literal">sysopen</tt> or three-argument <tt class="literal">open</tt>) to makethis happen automatically.  Imagine you have a simple Perl programlike this:<blockquote><pre class="programlisting">#!/usr/bin/perl -p# nl - number input linesprintf "%6d  ", $.;</pre></blockquote>Presuming you've arranged for the <tt class="literal">INPUT</tt> handle to stay open across<tt class="literal">exec</tt>s, you can call that program this way:<blockquote><pre class="programlisting">$fdspec = '&lt;&amp;=' . fileno(INPUT);system("nl", $fdspec);</pre></blockquote>or to catch the output:<blockquote><pre class="programlisting">@lines = `nl '$fdspec'`;  # single quotes protect spec from shell</pre></blockquote>Whether or not you <tt class="literal">exec</tt> another program, if you usefile descriptors inherited across <tt class="literal">fork</tt>, there's onesmall gotcha.  Unlike variables copied across a<tt class="literal">fork</tt>, which actually get duplicate but independentcopies, file descriptors really <em class="emphasis">are</em> the same inboth processes.  If one process reads data from the handle, the seekpointer (file position) advances in the other process, too, and thatdata is no longer available to either process.  If they take turnsreading, they'll leapfrog over each other in the file.  This makesintuitive sense for handles attached to serial devices, pipes, orsockets, since those tend to be read-only devices with ephemeral data.But this behavior may surprise you with disk files.  If this is aproblem, reopen any files that need separate tracking after the fork.</p><p><a name="INDEX-2981"></a>The <tt class="literal">fork</tt> operator is a concept derived from Unix, which means it mightnot be implemented correctly on all non-Unix/non-POSIX platforms.Notably, <tt class="literal">fork</tt> works on Microsoft systems only if you're running Perl5.6 (or better) on Windows 98 (or later).  Although <tt class="literal">fork</tt> isimplemented via multiple concurrent execution streams within the sameprogram on these systems, these aren't the sort of threads where alldata is shared by default; here, only file descriptors are.  See also<a href="ch17_01.htm">Chapter 17, "Threads"</a>.<a name="INDEX-2982"></a><a name="INDEX-2983"></a></p><a name="INDEX-2984"></a><a name="INDEX-2985"></a><!-- BOTTOM NAV BAR --><hr width="515" align="left"><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="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0"></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><tr><td align="left" valign="top" width="172">16.1. Signals</td><td align="center" valign="top" width="171"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0"></a></td><td align="right" valign="top" width="172">16.3. Pipes</td></tr></table></div><hr width="515" align="left"><!-- LIBRARY NAV BAR --><img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p><font size="-1"><a href="copyrght.htm">Copyright &copy; 2001</a> O'Reilly &amp; Associates. All rights reserved.</font></p><map name="library-map"> <area shape="rect" coords="2,-1,79,99" href="../index.htm"><area shape="rect" coords="84,1,157,108" href="../perlnut/index.htm"><area shape="rect" coords="162,2,248,125" href="../prog/index.htm"><area shape="rect" coords="253,2,326,130" href="../advprog/index.htm"><area shape="rect" coords="332,1,407,112" href="../cookbook/index.htm"><area shape="rect" coords="414,2,523,103" href="../sysadmin/index.htm"></map><!-- END OF BODY --></body></html>

⌨️ 快捷键说明

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