Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



16.21. Timing Out an Operation


16.21.1. Problem


You want to make sure an operation
doesn't take more than a certain amount of time. For instance, you're
running filesystem backups and want to abort if it takes longer than
an hour. Or, you want to give the user a limited amount of time to
respond to a query.

16.21.2. Solution



To interrupt a
long-running operation, set a SIGALRM handler to
call die, in effect transforming the signal into
an exception. Set an alarm with alarm, then
eval your code:

eval {
local $SIG{ALRM} = sub { die "alarm clock restart" };
alarm 10; # schedule alarm in 10 seconds
eval {
########
# long-running operation goes here
########
};
alarm 0; # cancel the alarm
};
alarm 0; # race condition protection
die if $@ && $@ !~ /alarm clock restart/; # reraise

16.21.3. Discussion


The alarm function takes one argument: the integer
number of seconds before the kernel sends your process a
SIGALRM, that is, an alarm signal. It may be
delivered after that time in busy time-sharing systems. The default
action for SIGALRM is to terminate your program,
so you should install your own signal handler.

Because this example should work no matter what operation is being
timed out, we take some special precautions in case your long-running
operation contains a slow syscall. Slow syscalls are those that don't
return immediately, but await some external event, such as for I/O to
happen or some sort of timer to go off. These external events include
read (including readline, the
<FH> operator), write,
and open on certain devices, fifos, and sockets,
as well as accept, connect,
send, recv,
flock, wait,
waitpid, and of course, sleep.
If the alarm hits while you're in a slow syscall and you simply catch
the signal and return, you'll go right back into that syscall. That's
because Perl automatically restarts syscalls where it's able to. The
only way out of them is to raise an exception through
die and then let eval catch it.
(This works because the exception winds up calling the C library's
longjmp(3) function, which is what really gets
you out of the restarting syscall.)

The nested exception trap is because you cannot be sure that
arbitrary code in your long-running operation isn't going to raise
some exception of its own. If it did, then that would pop you out of
the inner eval with the alarm still pending. You
need to make sure to clear the alarm anyway. The second
alarm 0 is in case the signal comes in after
running the long-running operation, but before getting to the first
alarm 0. If you don't do that, you would risk 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.

You cannot (usefully) give the alarm function a
fractional number of seconds; if you try, it will be truncated to an
integer. For precise timers, see
Recipe 3.9.

16.21.4. See Also


The "Signals" sections in Chapter 16 of Programming
Perl
and in perlipc(1); the section
on "Handling Race Conditions" in Chapter 23 of Programming
Perl
; the alarm function in Chapter 29
of Programming Perl and in
perlfunc(1);
Recipe 3.9



16.20. Blocking Signals16.22. Turning Signals into Fatal Errors




Copyright © 2003 O'Reilly & Associates. All rights reserved.

/ 875