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

📄 ch14.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 3 页
字号:
Another important point to keep in mind is that there is only

one <TT><FONT FACE="Courier">%SIG{}</FONT></TT> array in the Perl

script you are running. Setting an entry in <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

in one subroutine sets it for all objects in your program. There

is no &quot;<TT><FONT FACE="Courier">my</FONT></TT>&quot; <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

array with which you can set your own handler functions.

<P>

To set a signal handler, you use the following statement:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$SIG{INT} = \&amp;meHandleINT;</FONT></TT>

</BLOCKQUOTE>

<P>

In this statement, <TT><FONT FACE="Courier">meHandleINT</FONT></TT>

is a reference to a subroutine defined as something similar to

this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub meHandleSignals {<BR>

&nbsp;&nbsp;&nbsp;my $signame =&nbsp;&nbsp;shift;&nbsp;&nbsp;&nbsp;#Grab

signal name from passed input<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">die &quot;Caught

Signal: SIG$signame&quot;;<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

You can use the signal-handling function's name instead of the

reference; however, this is no longer the preferred, cool way

of doing things because references give a faster lookup. Therefore,

avoid setting handlers with statements like this one:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$SIG{INT} = 'meHandleINTs';</FONT></TT>

</BLOCKQUOTE>

<P>

You can use anonymous functions to install signal handlers. However,

be warned that some systems will not allow you to handle this

signal more than once, especially on System V machines where the

signal handler must be reinstalled every time it's hit. Use references

instead of trying a statement like this one:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$SIG{INT} = sub { die &quot;\nBye\n&quot;

};&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;&nbsp;Not portable</FONT></TT>

</BLOCKQUOTE>

<P>

By modifying the value of the reference in <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

entries, you can add or remove signal handlers. Listing 14.2 presents

an example. While the program is asleep, the signal handler <TT><FONT FACE="Courier">vocalHandler</FONT></TT>

can be called if the Ctrl+C key combination is pressed. However,

after the sleep session is over, the default value of <TT><FONT FACE="Courier">$SIG{INT}</FONT></TT>

is restored to allow the script to be killed via the default Ctrl+C

combination. Notice also how the hangup signal is set to be ignored

while the program is running with <TT><FONT FACE="Courier">$SIG{HUP}='IGNORE'</FONT></TT>

assignment.

<HR>

<BLOCKQUOTE>

<B>Listing 14.2. Signal handler usage.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2<BR>

&nbsp;3 sub vocalHandler

{<BR>

&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp; local($sig) = @_;<BR>

&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;Hey! Stop that! SIG$sig hurts! \n&quot;;<BR>

&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp; exit(1);<BR>

&nbsp;7 }<BR>

&nbsp;8<BR>

&nbsp;9 $SIG{INT} = \&amp;vocalHandler;

<BR>

</FONT></TT>Listing 14.2. continued <BR>

<TT><FONT FACE="Courier">10<BR>

11 $SIG{HUP} ='IGNORE';<BR>

12<BR>

13 printf &quot;\n I am about to sleep&quot;;<BR>

14<BR>

15 sleep (10);<BR>

16<BR>

17 print &quot;\n Restoring. default signal handler. &quot;;<BR>

18<BR>

19 $SIG{INT} ='DEFAULT';</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

The string <TT><FONT FACE="Courier">&quot;Hey!&#133;&quot;</FONT></TT>

will be printed out every time you hit the Ctrl+C key combination

during the 10-second interval that your Perl script is asleep.

<P>

There are two signal names that are reserved: <TT><FONT FACE="Courier">IGNORE</FONT></TT>

and <TT><FONT FACE="Courier">DEFAULT</FONT></TT>. When a signal

handler is set to <TT><FONT FACE="Courier">IGNORE</FONT></TT>,

Perl tries to discard the signal. When a signal handler is set

to <TT><FONT FACE="Courier">DEFAULT</FONT></TT>, Perl takes the

default action taken by functions called from within that block.

Some signals cannot be trapped or ignored (for example, the <TT><FONT FACE="Courier">KILL</FONT></TT>

and <TT><FONT FACE="Courier">STOP</FONT></TT> signals).

<P>

All modules and inherited objects affect the <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

hash. However, the <TT><FONT FACE="Courier">%SIG</FONT></TT> hash

can be redeclared in a function as a local variable to completely

mask out the default <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

hash. The original hash still remains, but due to scoping rules

in Perl, the local <TT><FONT FACE="Courier">%SIG{}</FONT></TT>

is used.

<P>

The <TT><FONT FACE="Courier">%SIG</FONT></TT> hash is not local

to each module unless you declare it as such. This is used to

disable signals temporarily within certain function calls. Here's

a sample fragment of code:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub warpper {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;local $SIG{INT} = 'IGNORE';&nbsp;&nbsp;&nbsp;#

declare a new SIG hash.<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">&nbsp;&nbsp;&nbsp;&nbsp;&amp;localFunction;&nbsp;&nbsp;#Then

call this function.<BR>

&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;sub localFunction {<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">&nbsp;&nbsp;&nbsp;&nbsp;#

interrupts are still ignored in this function.<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

Upon entry into the wrapper function, a local <TT><FONT FACE="Courier">%SIG</FONT></TT>

hash is created and the <TT><FONT FACE="Courier">INT</FONT></TT>

interrupt is set to be ignored. The <TT><FONT FACE="Courier">localFunction</FONT></TT>

is then undisturbed by <TT><FONT FACE="Courier">SIGINT</FONT></TT>.

On exiting from the wrapper function, the <TT><FONT FACE="Courier">%SIG</FONT></TT>

hash in the main module is the default array. Therefore, the values

in the <TT><FONT FACE="Courier">%SIG</FONT></TT> hash are inherited

by the lower modules.

<H2><A NAME="ThekillFunction"><FONT SIZE=5 COLOR=#FF0000>The </FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">kill()</FONT></TT><FONT SIZE=5 COLOR=#FF0000>

Function</FONT></A></H2>

<P>

The <TT><FONT FACE="Courier">kill()</FONT></TT> function is used

to send the <TT><FONT FACE="Courier">KILL</FONT></TT> signal to

a process or a set of processes. The first parameter of the <TT><FONT FACE="Courier">kill()</FONT></TT>

function is the signal number, followed by a list of process IDs.

The usual UNIX permissions apply. Your script must own the process

it's about to blow out of the water. That is, the effective and

real UID (user ID) must be the same for the process sending the

signal and the process receiving the signal. Here's the syntax

for the <TT><FONT FACE="Courier">kill()</FONT></TT> function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">kill signalNumber,processID</FONT></TT>

</BLOCKQUOTE>

<P>

You can specify more than one process on the line by the command:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">kill signalNumber,processID, processID,

....</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">kill</FONT></TT> function can be

used to terminate a lot of processes at once. All processes in

a process group can be terminated by another process in the group

by sending a negative <TT><FONT FACE="Courier">processID</FONT></TT>.

Such measures are taken by daemons that terminate all child processes.

The use of the blanket <TT><FONT FACE="Courier">kill</FONT></TT>

keeps you from keeping a table of process IDs of all the child

processes for an application program. The process making the call

with the negative ID is exempt from this pillage. That is, all

the rest of the processes, except the one making the call, will

be killed. The syntax for this call would be of the following

form:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">kill(9, -$$);</FONT></TT>

</BLOCKQUOTE>

<P>

To see whether a particular task is alive, you can use signal

0 with the <TT><FONT FACE="Courier">kill</FONT></TT> function.

A non-zero return value tells you that the task is alive; a zero

value tells you that the task does not exist.

<BLOCKQUOTE>

<TT><FONT FACE="Courier">if&nbsp;&nbsp;(kill(0,$id)) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;print &quot;Task&nbsp;&nbsp;$id is alive;

<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">}&nbsp;&nbsp;&nbsp;&nbsp;else

{<BR>

&nbsp;&nbsp;&nbsp;&nbsp;print &quot;Task&nbsp;&nbsp;$id is dead&quot;;

<BR>

}</FONT></TT>

</BLOCKQUOTE>

<H2><A NAME="ThewarnFunction"><FONT SIZE=5 COLOR=#FF0000>The </FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">warn()</FONT></TT><FONT SIZE=5 COLOR=#FF0000>

Function</FONT></A></H2>

<P>

Sometimes in Perl scripts you have to warn the user about certain

conditions in the system by writing to the console. Normally,

you use the <TT><FONT FACE="Courier">die()</FONT></TT> function

to print the cause of death of a Perl script just before bailing

out. If you did not want to stop right at the cause of the error

but rather limp along with an error message only, a <TT><FONT FACE="Courier">print</FONT></TT>

statement may be redirected to some file. In this case, you would

use the <TT><FONT FACE="Courier">warn</FONT></TT> function. The

<TT><FONT FACE="Courier">warn</FONT></TT> function in Perl is

the same as the <TT><FONT FACE="Courier">die</FONT></TT> function,

except that the program keeps going with the <TT><FONT FACE="Courier">warn</FONT></TT>

function instead of stopping as it would with <TT><FONT FACE="Courier">die</FONT></TT>.

<H2><A NAME="Timeouts"><FONT SIZE=5 COLOR=#FF0000>Timeouts</FONT></A>

</H2>

<P>

You can use signals to handle timeouts in UNIX. The alarm function

comes in handy for these types of signals. Here's the syntax for

the <TT><FONT FACE="Courier">alarm()</FONT></TT> function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">alarm numberOfseconds;</FONT></TT>

</BLOCKQUOTE>

<P>

For example, the following stub of code sets up <TT><FONT FACE="Courier">SIGALRM</FONT></TT>

for a program:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub aclk {<BR>

my&nbsp;&nbsp;$is = shift;<BR>

print &quot;something&quot;;<BR>

}<BR>

<BR>

$SIG{ALRM} = \&amp;clk;</FONT></TT>

</BLOCKQUOTE>

<P>

You can wait for a child process, too, with the <TT><FONT FACE="Courier">wait</FONT></TT>

command. The <TT><FONT FACE="Courier">wait</FONT></TT> command

returns after a child process dies and returns the process ID

of the dead child process. Calling the wait function may cause

you to hang forever if the child runs away and never dies. If

there are no children, this function returns <TT><FONT FACE="Courier">-1</FONT></TT>.

To wait explicitly for a process, you can specify its process

ID in the call to<B> </B><TT><FONT FACE="Courier">waitpid</FONT></TT>.

The syntax for the call is <TT><FONT FACE="Courier">waitpid $PID

0</FONT></TT>. The zero is required.

<H2><A NAME="PipesandFIFOs"><FONT SIZE=5 COLOR=#FF0000>Pipes and

FIFOs</FONT></A></H2>

<P>

A UNIX system call to <TT><FONT FACE="Courier">pipe()</FONT></TT>

can be used to create a communications channel between two processes.

Generally you call this function just before a fork call and then

use the pipe to communicate between a parent process and its child

process. Contrast this usage of pipes with message queues, which

can be used to communication between unrelated processes. Here's

the syntax for this call:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">pipe ( READHANDLE, WRITEHANDLE);</FONT></TT>

</BLOCKQUOTE>

<P>

Listing 14.3 illustrates a sample run of a pipe communication.

<HR>

<BLOCKQUOTE>

<B>Listing 14.3. A sample run when using pipes.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 $|=1;<BR>

&nbsp;3 #<BR>

&nbsp;4 # Create a pipe with the system call<BR>

&nbsp;5 #<BR>

&nbsp;6 $smoke = pipe(PIPE_R, PIPE_W);<BR>

&nbsp;7 #<BR>

&nbsp;8 # Fork off (almost) immediately.<BR>

&nbsp;9 #<BR>

10 if ($pid = fork) {<BR>

11&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n Parent:&quot;;<BR>

12&nbsp;&nbsp;&nbsp;&nbsp; close PIPE_R;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

&lt;-- the handle you do not need.<BR>

13&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

14&nbsp;&nbsp;&nbsp;&nbsp; # now write to the child.<BR>

15&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

16&nbsp;&nbsp;&nbsp;&nbsp; select PIPE_W;<BR>

17&nbsp;&nbsp;&nbsp;&nbsp; for ($i=0;$i&lt;5;$i++) {<BR>

18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 1;<BR>

19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf PIPE_W

&quot;[Sending: %d]\n&quot;, $i;<BR>

20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

21&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

22&nbsp;&nbsp;&nbsp;&nbsp; else<BR>

23&nbsp;&nbsp;&nbsp;&nbsp; {<BR>

24&nbsp;&nbsp;&nbsp;&nbsp; printf &quot;\n Child:&quot;;<BR>

25&nbsp;&nbsp;&nbsp;&nbsp; close PIPE_W;&nbsp;&nbsp;&nbsp;# &lt;-

won't be writing to it.<BR>

26&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

27&nbsp;&nbsp;&nbsp;&nbsp; # now read from parent<BR>

28&nbsp;&nbsp;&nbsp;&nbsp; #<BR>

29&nbsp;&nbsp;&nbsp;&nbsp; for ($i=0;$i&lt;5;$i++) {<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$buf =

&lt;PIPE_R&gt;;<BR>

31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# For

⌨️ 快捷键说明

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