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

📄 ch16_01.htm

📁 编程珍珠,里面很多好用的代码,大家可以参考学习呵呵,
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<a name="INDEX-2920"></a><a name="INDEX-2921"></a><a name="INDEX-2922"></a><a name="INDEX-2923"></a>Processes (under Unix, at least) are organized into process groups,generally corresponding to an entire job.  For example, when you fireoff a single shell command that consists of a series of filtercommands that pipe data from one to the other, those processes (andtheir child processes) all belong to the same process group.  Thatprocess group has a number corresponding to the process number of theprocess group leader.  If you send a signal to a positive processnumber, it just sends the signal to the process, but if you send asignal to a negative number, it sends that signal to every processwhose process group number is the corresponding positive number, thatis, the process number of the process group leader.  (Conveniently forthe process group leader, the process group ID is just<tt class="literal">$$</tt>.)</p><p><a name="INDEX-2924"></a>Suppose your program wants to send a hang-up signal to all childprocesses it started directly, plus any grandchildren started by thosechildren, plus any greatgrandchildren started by those grandchildren,and so on.  To do this, your program first calls<tt class="literal">setpgrp(0,0)</tt> to become the leader of a new processgroup, and any processes it creates will be part of the new group.  Itdoesn't matter whether these processes were started manually via<tt class="literal">fork</tt>, automaticaly via piped<tt class="literal">open</tt>s, or as backgrounded jobs with<tt class="literal">system("cmd &amp;")</tt>.  Even if thoseprocesses had children of their own, sending a hang-up signal to yourentire process group will find them all (except for processes thathave set their own process group or changed their UID to givethemselves diplomatic immunity to your signals).<blockquote><pre class="programlisting">{    local $SIG{HUP} = 'IGNORE';   # exempt myself    kill(HUP, -$$);               # signal my own process group}</pre></blockquote><a name="INDEX-2925"></a><a name="INDEX-2926"></a></p><p>Another interesting signal is signal number <tt class="literal">0</tt>.  Thisdoesn't actually affect the target process, but instead checksthat it's alive and hasn't changed its UID.  That is, it checkswhether it's legal to send a signal, without actually sending one.<blockquote><pre class="programlisting">unless (kill 0 =&gt; $kid_pid) {    warn "something wicked happened to $kid_pid";}</pre></blockquote><a name="INDEX-2927"></a><a name="INDEX-2928"></a>Signal number <tt class="literal">0</tt> is the only signal that works thesame under Microsoft ports of Perl as it does in Unix.  On Microsoftsystems, <tt class="literal">kill</tt> does not actually deliver a signal.Instead, it forces the target process to exit with the statusindicated by the signal number.  This may be fixed someday.  The magic<tt class="literal">0</tt> signal, however, still behaves in the standard,nondestructive fashion.</p><h3 class="sect2">16.1.2. Reaping Zombies</h3><a name="INDEX-2929"></a><a name="INDEX-2930"></a><a name="INDEX-2931"></a><a name="INDEX-2932"></a><p><a name="INDEX-2933"></a><a name="INDEX-2934"></a>When a process exits, its parent is sent a <tt class="literal">CHLD</tt>signal by the kernel and the process becomes a zombie<a href="#FOOTNOTE-4">[4]</a> until theparent calls <tt class="literal">wait</tt> or <tt class="literal">waitpid</tt>.If you start another process in Perl using anything except<tt class="literal">fork</tt>, Perl takes care of reaping your zombiedchildren, but if you use a raw <tt class="literal">fork</tt>, you'reexpected to clean up after yourself.  On many but not all kernels, asimple hack for autoreaping zombies is to set<tt class="literal">$SIG{CHLD}</tt> to <tt class="literal">'IGNORE'</tt>.  A moreflexible (but tedious) approach is to reap them yourself.  Becausemore than one child may have died before you get around to dealingwith them, you must gather your zombies in a loop until there aren'tany more:<blockquote><pre class="programlisting">use POSIX ":sys_wait_h";sub REAPER { 1 until waitpid(-1, WNOHANG) == -1) }</pre></blockquote>To run this code as needed, you can either set a <tt class="literal">CHLD</tt> signalhandler for it:<blockquote><pre class="programlisting">$SIG{CHLD} = \&amp;REAPER;</pre></blockquote>or, if you're running in a loop, just arrange to call the reaperevery so often.  This is the best approach because it isn't subjectto the occasional core dump that signals can sometimes trigger inthe C library.  However, it's expensive if called in a tight loop, so areasonable compromise is to use a hybrid strategy where you minimizethe risk within the handler by doing as little as possible and waiting until outside to reap zombies:<blockquote><pre class="programlisting">our $zombies = 0;$SIG{CHLD} = sub { $zombies++ };  sub reaper {    my $zombie;    our %Kid_Status;  # store each exit status    $zombies = 0;      while (($zombie = waitpid(-1, WNOHANG)) != -1) {        $Kid_Status{$zombie} = $?;    } }while (1) {    reaper() if $zombies;    ...}</pre></blockquote><a name="INDEX-2935"></a><a name="INDEX-2936"></a><a name="INDEX-2937"></a>This code assumes your kernel supports reliable signals.  Old SysVtraditionally didn't, which made it impossible to write correctsignal handlers there.  Ever since way back in the 5.003 release,Perl has used the <em class="emphasis">sigaction</em>(2) syscall where available, which is a lotmore dependable.  This means that unless you're running on an ancientoperating system or with an ancient Perl, you won't have to reinstallyour handlers and risk missing signals.  Fortunately, all BSD-flavoredsystems (including Linux, Solaris, and Mac OS X) plus all POSIX-compliantsystems provide reliable signals, so the old broken SysV behavioris more a matter of historical note than of current concern.<a name="INDEX-2938"></a></p><blockquote class="footnote"><a name="FOOTNOTE-4"></a><p>[4]Yes, that really is the technical term.</p></blockquote><p><a name="INDEX-2939"></a>With these newer kernels, many other things will workbetter, too.  For example, "slow" syscalls (those that can block,like <tt class="literal">read</tt>, <tt class="literal">wait</tt>, and <tt class="literal">accept</tt>) will restartautomatically if interrupted by a signal.  In the bad old days,user code had to remember to check explicitly whether each slowsyscall failed with <tt class="literal">$!</tt> (<tt class="literal">$ERRNO</tt>) set to <tt class="literal">EINTR</tt> and, if so, restart.   This wouldn't happen just from <tt class="literal">INT</tt> signals; even innocuoussignals like <tt class="literal">TSTP</tt> (from a Control-Z) or <tt class="literal">CONT</tt> (from foregrounding thejob) would abort the syscall.  Perl now restarts the syscall for youautomatically if the operating system allows it to.  This isgenerally construed to be a feature.</p><p>You can check whether you have the more rigorous POSIX-style signalbehavior by loading the <tt class="literal">Config</tt> module and checkingwhether <tt class="literal">$Config{d_sigaction}</tt> has a true value.  To find outwhether slow syscalls are restartable, check your system documentationon <em class="emphasis">sigaction</em>(2) or <em class="emphasis">sigvec</em>(3), or scrounge around your C<em class="emphasis">sys/signal.h</em> file for <tt class="literal">SV_INTERRUPT</tt> or <tt class="literal">SA_RESTART</tt>.  If oneor both symbols are found, you probably have restartable syscalls.</p><h3 class="sect2">16.1.3. Timing Out Slow Operations</h3><a name="INDEX-2940"></a><a name="INDEX-2941"></a><a name="INDEX-2942"></a><p><a name="INDEX-2943"></a>A common use for signals is to impose time limits on long-runningoperations.  If you're on a Unix system (or any other POSIX-conformingsystem that supports the <tt class="literal">ALRM</tt> signal), you can ask the kernelto send your process an <tt class="literal">ALRM</tt> at some point in the future:<blockquote><pre class="programlisting">use Fcntl ':flock';eval {     local $SIG{ALRM} = sub { die "alarm clock restart" };    alarm 10;               # schedule alarm in 10 seconds     eval {         flock(FH, LOCK_EX)  # a blocking, exclusive lock            or die "can't flock: $!";    };    alarm 0;                # cancel the alarm};alarm 0;               # race condition protectiondie if $@ &amp;&amp; $@ !~ /alarm clock restart/; # reraise</pre></blockquote><a name="INDEX-2944"></a>If the alarm hits while you're waiting for the lock, and you simplycatch the signal and return, you'll go right back into the <tt class="literal">flock</tt>because Perl automatically restarts syscalls where it can.The only way out is to raise an exception through <tt class="literal">die</tt> and thenlet <tt class="literal">eval</tt> catch it.  (This works because the exception winds upcalling the C library's <em class="emphasis">longjmp</em>(3) function, which is what reallygets you out of the restarting syscall.)</p><p>The nested exception trap is included because calling <tt class="literal">flock</tt> would raisean exception if <tt class="literal">flock</tt> is not implemented on your platform, and you needto make sure to clear the alarm anyway.  The second <tt class="literal">alarm 0</tt> is provided in case the signal comes in after running the <tt class="literal">flock</tt> but beforegetting to the first <tt class="literal">alarm 0</tt>.   Without the second <tt class="literal">alarm</tt>, you wouldrisk a tiny race condition--but size doesn't matter in race conditions;they either exist or they don't.  And we prefer that they don't.</p><h3 class="sect2">16.1.4. Blocking Signals</h3><p><a name="INDEX-2945"></a><a name="INDEX-2946"></a><a name="INDEX-2947"></a><a name="INDEX-2948"></a>Now and then, you'd like to delay receipt of a signal during somecritical section of code.  You don't want to blindly ignore thesignal, but what you're doing is too important to interrupt.  Perl's<tt class="literal">%SIG</tt> hash doesn't implement signal blocking, but the <tt class="literal">POSIX</tt>module does, through its interface to the <em class="emphasis">sigprocmask</em>(2) syscall:<blockquote><pre class="programlisting">use POSIX qw(:signal_h);$sigset   = POSIX::SigSet-&gt;new; $blockset = POSIX::SigSet-&gt;new(SIGINT, SIGQUIT, SIGCHLD);       sigprocmask(SIG_BLOCK, $blockset, $sigset)     or die "Could not block INT,QUIT,CHLD signals: $!\n";</pre></blockquote>Once the three signals are all blocked, you can do whatever you wantwithout fear of being bothered.  When you're done withyour critical section, unblock the signals by restoring the old signal mask:  <blockquote><pre class="programlisting">sigprocmask(SIG_SETMASK, $sigset)    or die "Could not restore INT,QUIT,CHLD signals: $!\n";</pre></blockquote>If any of the three signals came in while blocked, they are deliveredimmediately.  If two or more different signals are pending, theorder of delivery is not defined.  Additionally, no distinction ismade between having received a particular signal once while blockedand having received it many times.<a href="#FOOTNOTE-5">[5]</a> Forexample, if nine child processes exited while you were blocking<tt class="literal">CHLD</tt> signals, your handler (if you had one) would still be calledonly once after you unblocked.  That's why, when you reap zombies,you should always loop until they're all gone.</p><blockquote class="footnote"><a name="FOOTNOTE-5"></a><p>[5] Traditionally, that is. Countable signals may be implemented on some real-time systems accordingto the latest specs, but we haven't seen these yet.</p></blockquote><a name="INDEX-2949"></a><a name="INDEX-2950"></a><a name="INDEX-3117"></a><a name="INDEX-3118"></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="ch15_03.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_02.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr><tr><td align="left" valign="top" width="172">15.3. Caution, <img src="figs/ren2_bold.gif"> Working</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.2. Files</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 + -