perlipc.html
来自「perl教程」· HTML 代码 · 共 765 行 · 第 1/5 页
HTML
765 行
<span class="keyword">sub</span><span class="variable"> precious </span><span class="operator">{</span>
<span class="keyword">local</span> <span class="variable">$SIG</span><span class="operator">{</span><span class="string">INT</span><span class="operator">}</span> <span class="operator">=</span> <span class="string">'IGNORE'</span><span class="operator">;</span>
<span class="operator">&</span><span class="variable">more_functions</span><span class="operator">;</span>
<span class="operator">}</span>
<span class="keyword">sub</span><span class="variable"> more_functions </span><span class="operator">{</span>
<span class="comment"># interrupts still ignored, for now...</span>
<span class="operator">}</span>
</pre>
<p>Sending a signal to a negative process ID means that you send the signal
to the entire Unix process-group. This code sends a hang-up signal to all
processes in the current process group (and sets $SIG{HUP} to IGNORE so
it doesn't kill itself):</p>
<pre>
<span class="operator">{</span>
<span class="keyword">local</span> <span class="variable">$SIG</span><span class="operator">{</span><span class="string">HUP</span><span class="operator">}</span> <span class="operator">=</span> <span class="string">'IGNORE'</span><span class="operator">;</span>
<span class="keyword">kill</span> <span class="string">HUP</span> <span class="operator">=></span> <span class="operator">-</span><span class="variable">$$</span><span class="operator">;</span>
<span class="comment"># snazzy writing of: kill('HUP', -$$)</span>
<span class="operator">}</span>
</pre>
<p>Another interesting signal to send is signal number zero. This doesn't
actually affect a child process, but instead checks whether it's alive
or has changed its UID.</p>
<pre>
<span class="keyword">unless</span> <span class="operator">(</span><span class="keyword">kill</span> <span class="number">0</span> <span class="operator">=></span> <span class="variable">$kid_pid</span><span class="operator">)</span> <span class="operator">{</span>
<span class="keyword">warn</span> <span class="string">"something wicked happened to $kid_pid"</span><span class="operator">;</span>
<span class="operator">}</span>
</pre>
<p>When directed at a process whose UID is not identical to that
of the sending process, signal number zero may fail because
you lack permission to send the signal, even though the process is alive.
You may be able to determine the cause of failure using <a href="../../lib/Pod/perlvar.html#item___"><code>%!</code></a>.</p>
<pre>
<span class="keyword">unless</span> <span class="operator">(</span><span class="keyword">kill</span> <span class="number">0</span> <span class="operator">=></span> <span class="variable">$pid</span> <span class="keyword">or</span> <span class="variable">$!</span><span class="operator">{</span><span class="string">EPERM</span><span class="operator">}</span><span class="operator">)</span> <span class="operator">{</span>
<span class="keyword">warn</span> <span class="string">"$pid looks dead"</span><span class="operator">;</span>
<span class="operator">}</span>
</pre>
<p>You might also want to employ anonymous functions for simple signal
handlers:</p>
<pre>
<span class="variable">$SIG</span><span class="operator">{</span><span class="string">INT</span><span class="operator">}</span> <span class="operator">=</span> <span class="keyword">sub</span><span class="variable"> </span><span class="operator">{</span> <span class="keyword">die</span> <span class="string">"\nOutta here!\n"</span> <span class="operator">};</span>
</pre>
<p>But that will be problematic for the more complicated handlers that need
to reinstall themselves. Because Perl's signal mechanism is currently
based on the <code>signal(3)</code> function from the C library, you may sometimes be so
misfortunate as to run on systems where that function is "broken", that
is, it behaves in the old unreliable SysV way rather than the newer, more
reasonable BSD and POSIX fashion. So you'll see defensive people writing
signal handlers like this:</p>
<pre>
<span class="keyword">sub</span><span class="variable"> REAPER </span><span class="operator">{</span>
<span class="variable">$waitedpid</span> <span class="operator">=</span> <span class="keyword">wait</span><span class="operator">;</span>
<span class="comment"># loathe sysV: it makes us not only reinstate</span>
<span class="comment"># the handler, but place it after the wait</span>
<span class="variable">$SIG</span><span class="operator">{</span><span class="string">CHLD</span><span class="operator">}</span> <span class="operator">=</span> <span class="operator">\&</span><span class="variable">REAPER</span><span class="operator">;</span>
<span class="operator">}</span>
<span class="variable">$SIG</span><span class="operator">{</span><span class="string">CHLD</span><span class="operator">}</span> <span class="operator">=</span> <span class="operator">\&</span><span class="variable">REAPER</span><span class="operator">;</span>
<span class="comment"># now do something that forks...</span>
</pre>
<p>or better still:</p>
<pre>
<span class="keyword">use</span> <span class="variable">POSIX</span> <span class="string">":sys_wait_h"</span><span class="operator">;</span>
<span class="keyword">sub</span><span class="variable"> REAPER </span><span class="operator">{</span>
<span class="keyword">my</span> <span class="variable">$child</span><span class="operator">;</span>
<span class="comment"># If a second child dies while in the signal handler caused by the</span>
<span class="comment"># first death, we won't get another signal. So must loop here else</span>
<span class="comment"># we will leave the unreaped child as a zombie. And the next time</span>
<span class="comment"># two children die we get another zombie. And so on.</span>
<span class="keyword">while</span> <span class="operator">((</span><span class="variable">$child</span> <span class="operator">=</span> <span class="keyword">waitpid</span><span class="operator">(-</span><span class="number">1</span><span class="operator">,</span><span class="variable">WNOHANG</span><span class="operator">))</span> <span class="operator">></span> <span class="number">0</span><span class="operator">)</span> <span class="operator">{</span>
<span class="variable">$Kid_Status</span><span class="operator">{</span><span class="variable">$child</span><span class="operator">}</span> <span class="operator">=</span> <span class="variable">$?</span><span class="operator">;</span>
<span class="operator">}</span>
<span class="variable">$SIG</span><span class="operator">{</span><span class="string">CHLD</span><span class="operator">}</span> <span class="operator">=</span> <span class="operator">\&</span><span class="variable">REAPER</span><span class="operator">;</span> <span class="comment"># still loathe sysV</span>
<span class="operator">}</span>
<span class="variable">$SIG</span><span class="operator">{</span><span class="string">CHLD</span><span class="operator">}</span> <span class="operator">=</span> <span class="operator">\&</span><span class="variable">REAPER</span><span class="operator">;</span>
<span class="comment"># do something that forks...</span>
</pre>
<p>Signal handling is also used for timeouts in Unix, While safely
protected within an <a href="../../lib/Pod/perlfunc.html#item_eval"><code>eval{}</code></a> block, you set a signal handler to trap
alarm signals and then schedule to have one delivered to you in some
number of seconds. Then try your blocking operation, clearing the alarm
when it's done but not before you've exited your <a href="../../lib/Pod/perlfunc.html#item_eval"><code>eval{}</code></a> block. If it
goes off, you'll use <a href="../../lib/Pod/perlfunc.html#item_die"><code>die()</code></a> to jump out of the block, much as you might
using <code>longjmp()</code> or <code>throw()</code> in other languages.</p>
<p>Here's an example:</p>
<pre>
<span class="keyword">eval</span> <span class="operator">{</span>
<span class="keyword">local</span> <span class="variable">$SIG</span><span class="operator">{</span><span class="string">ALRM</span><span class="operator">}</span> <span class="operator">=</span> <span class="keyword">sub</span><span class="variable"> </span><span class="operator">{</span> <span class="keyword">die</span> <span class="string">"alarm clock restart"</span> <span class="operator">};</span>
<span class="keyword">alarm</span> <span class="number">10</span><span class="operator">;</span>
<span class="keyword">flock</span><span class="operator">(</span><span class="variable">FH</span><span class="operator">,</span> <span class="number">2</span><span class="operator">);</span> <span class="comment"># blocking write lock</span>
<span class="keyword">alarm</span> <span class="number">0</span><span class="operator">;</span>
<span class="operator">};</span>
<span class="keyword">if</span> <span class="operator">(</span><span class="variable">$@</span> <span class="keyword">and</span> <span class="variable">$@</span> <span class="operator">!~</span> <span class="regex">/alarm clock restart/</span><span class="operator">)</span> <span class="operator">{</span> <span class="keyword">die</span> <span class="operator">}</span>
</pre>
<p>If the operation being timed out is <a href="../../lib/Pod/perlfunc.html#item_system"><code>system()</code></a> or qx(), this technique
is liable to generate zombies. If this matters to you, you'll
need to do your own <a href="../../lib/Pod/perlfunc.html#item_fork"><code>fork()</code></a> and exec(), and kill the errant child process.</p>
<p>For more complex signal handling, you might see the standard POSIX
module. Lamentably, this is almost entirely undocumented, but
the <em>t/lib/posix.t</em> file from the Perl source distribution has some
examples in it.</p>
<p>
</p>
<h2><a name="handling_the_sighup_signal_in_daemons">Handling the SIGHUP Signal in Daemons</a></h2>
<p>A process that usually starts when the system boots and shuts down
when the system is shut down is called a daemon (Disk And Execution
MONitor). If a daemon process has a configuration file which is
modified after the process has been started, there should be a way to
tell that process to re-read its configuration file, without stopping
the process. Many daemons provide this mechanism using the <code>SIGHUP</code>
signal handler. When you want to tell the daemon to re-read the file
you simply send it the <code>SIGHUP</code> signal.</p>
<p>Not all platforms automatically reinstall their (native) signal
handlers after a signal delivery. This means that the handler works
only the first time the signal is sent. The solution to this problem
is to use <code>POSIX</code> signal handlers if available, their behaviour
is well-defined.</p>
<p>The following example implements a simple daemon, which restarts
itself every time the <code>SIGHUP</code> signal is received. The actual code is
located in the subroutine <code>code()</code>, which simply prints some debug
info to show that it works and should be replaced with the real code.</p>
<pre>
<span class="comment">#!/usr/bin/perl -w</span>
</pre>
<pre>
<span class="keyword">use</span> <span class="variable">POSIX</span> <span class="operator">();</span>
<span class="keyword">use</span> <span class="variable">FindBin</span> <span class="operator">();</span>
<span class="keyword">use</span> <span class="variable">File::Basename</span> <span class="operator">();</span>
<span class="keyword">use</span> <span class="variable">File::Spec::Functions</span><span class="operator">;</span>
</pre>
<pre>
<span class="variable">$|</span><span class="operator">=</span><span class="number">1</span><span class="operator">;</span>
</pre>
<pre>
<span class="comment"># make the daemon cross-platform, so exec always calls the script</span>
<span class="comment"># itself with the right path, no matter how the script was invoked.</span>
<span class="keyword">my</span> <span class="variable">$script</span> <span class="operator">=</span> <span class="variable">File::Basename::basename</span><span class="operator">(</span><span class="variable">$0</span><span class="operator">);</span>
<span class="keyword">my</span> <span class="variable">$SELF</span> <span class="operator">=</span> <span class="variable">catfile</span> <span class="variable">$FindBin::Bin</span><span class="operator">,</span> <span class="variable">$script</span><span class="operator">;</span>
</pre>
<pre>
<span class="comment"># POSIX unmasks the sigprocmask properly</span>
<span class="keyword">my</span> <span class="variable">$sigset</span> <span class="operator">=</span> <span class="variable">POSIX::SigSet</span><span class="operator">-></span><span class="variable">new</span><span class="operator">();</span>
<span class="keyword">my</span> <span class="variable">$action</span> <span class="operator">=</span> <span class="variable">POSIX::SigAction</span><span class="operator">-></span><span class="variable">new</span><span class="operator">(</span><span class="string">'sigHUP_handler'</span><span class="operator">,</span>
<span class="variable">$sigset</span><span class="operator">,</span>
<span class="operator">&</span><span class="variable">POSIX::SA_NODEFER</span><span class="operator">);</span>
<span class="variable">POSIX::sigaction</span><span class="operator">(&</span><span class="variable">POSIX::SIGHUP</span><span class="operator">,</span> <span class="variable">$action</span><span class="operator">);</span>
</pre>
<pre>
<span class="keyword">sub</span><span class="variable"> sigHUP_handler </span><span class="operator">{</span>
<span class="keyword">print</span> <span class="string">"got SIGHUP\n"</span><span class="operator">;</span>
<span class="keyword">exec</span><span class="operator">(</span><span class="variable">$SELF</span><span class="operator">,</span> <span class="variable">@ARGV</span><span class="operator">)</span> <span class="keyword">or</span> <span class="keyword">die</span> <span class="string">"Couldn't restart: $!\n"</span><span class="operator">;</span>
<span class="operator">}</span>
</pre>
<pre>
<span class="variable">code</span><span class="operator">();</span>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?