moderated >> Timed operations with eval/die -- race?

by Nitzan Shaked » Mon, 27 Jun 2005 23:01:07 GMT

(Cross-posted to cplmisc -- sorry for not doing it at once, and hope
this is acceptable policy).

Hi all


I need to do a timed operation: ie give up after some time if it does
not finish. From what I can gather the "canon" way of doing this is:


eval {
local $SIG{ALRM} = sub { die "alarm\n"; };
alarm 10; ## for example
$result = my_operation();
alarm 0;


};


if ( $@ ) {
die unless $@ eq "alarm\n";
## CODE IF TIMED-OUT

} else {


## CODE IF DID NOT TIME OUT


}


However, it strikes me as if there's a race here, and I can't find
proof to the contrary in the documentation:

==> What happens if my_operation() is performed, finishes on time, even

$result is set, ... BUT the alarm expires (is set) before running
"alarm 0", that is: "between" the lines "$result=..." and "alarm 0;".


In that case the operation was performed but I will not know that, or
think that it was not.


Specifically, I want to spawn child processes and wait for them, but
not more than "x" seconds. Is there a better way to do this other than
fork() and then:
1) Have the parent wait for it's children?
2) Have the children call exec()?


Of course I realize the race in my case is not terrible: worst case the

parent will try to kill a PID which was already "reaped". If that
doesn't happen before pid's overflow and start back from 1 (and it
won't in reality...) I am safe.


Still, is there no safe way of doing this?


moderated >> Timed operations with eval/die -- race?

by Ilya Zakharevich » Wed, 29 Jun 2005 04:53:05 GMT


[A complimentary Cc of this posting was sent to
Nitzan Shaked
< XXXX@XXXXX.COM >], who wrote in article < XXXX@XXXXX.COM >:


If you can't define "finish", there is no bullet proof way to time
out. This is why databases with rollbacks are like rocket science.


Definitely.


What if it finishes, but $result is not set? What if it finished, but
the subroutine which made the final touches did not have time to
execute return()?


About 7 years ago I checked that I can overflow the pid counter in
about 6min; the processor is now more than 10 years old. With
processors of today the risk of the counter overflowing between two
instructions is very real.


I do not think so. Unless the fact of being "finished" is atomic, and
can be checked after die()ing...

Hope this helps,
Ilya

moderated >> Timed operations with eval/die -- race?

by Big and Blue » Wed, 29 Jun 2005 05:11:21 GMT


my/local/our? $done;


$done = 0;
local $SIG{ALRM} = sub { die "alarm\n" unless $done; };


my_operation sets $done as soon as it reached a state which it
considers as "done". Will reduce the race condition.


--
Just because I've written it doesn't mean that
either you or I have to believe it.

Similar Threads

1. (Newbie) Timed operations with eval/die

Hi all

I need to do a timed operation: ie give up after some time if it does
not finish. From what I can gather the "canon" way of doing this is:

eval {
    local $SIG{ALRM} = sub { die "alarm\n"; };
    alarm 10; ## for example
    $result = my_operation();
    alarm 0;
};
if ( $@ ) {
    die unless $@ eq "alarm\n";
    ## CODE IF TIMED-OUT
} else {
    ## CODE IF DID NOT TIME OUT
}

However, it strikes me as if there's a race here, and I can't find
proof to the contrary in the documentation:

==> What happens if my_operation() is performed, finishes on time, even
$result is set, ... BUT the alarm expires (is set) before running
"alarm 0", that is: "between" the lines "$result=..." and "alarm 0;".

In that case the operation was performed but I will not know that, or
think that it was not.

Specifically, I want to spawn child processes and wait for them, but
not more than "x" seconds. Is there a better way to do this other than
fork() and then:
1) Have the parent wait for it's children?
2) Have the children call exec()?

Of course I realize the race in my case is not terrible: worst case the
parent will try to kill a PID which was already "reaped". If that
doesn't happen before pid's overflow and start back from 1 (and it
won't in reality...) I am safe.

Still, is there no safe way of doing this?

2. *main::exit = sub {die @_,"\n"} (was: eval exit/exec) - Perl

3. Timing an operation

Dear All,

Merry Christmas!! 

Wondering if someone can recommend the best way to time an operation within
a script.

I'm using Net:FTP to check transmission times on files to various computers
for later comparison.  
I see the benchmark module, but I'm thinking take a timestamp, running the
ftp transfer, then running again when complete and diffing the two..

Any other recommendations?

Cheers,

Mark

4. timing out slow operations - Perl

5. eval EXPR with maximum execution time?

Hi,

I'm looking for something that is like eval in that it can compile and
run code from strings, but will quit after a maximum given time.

The benchmark module tool "timethis" is very close, but it can only
ever specify a minimum time to iterate the given code.  What I want is
code that iterates ONCE, breaking at a maximum time that I can specify
(if it runs that long).

If anybody knows of a function to do this I would appreciate it.  I
would rather not have to start digging around in the source for
timethis to create my own.

Thanks.

6. Different behavior between eval "07" and eval "08" - Perl

7. [DGBI] to die or not to die (was: opening a file)

On 2009-01-14, Jrgen Exner < XXXX@XXXXX.COM > wrote:
> cartercc < XXXX@XXXXX.COM > wrote:
>>On Jan 10, 8:07am, Tad J McClellan < XXXX@XXXXX.COM > wrote:
>>> You should always, yes *always*, check the return value from open():
>>
>>Like other ironclad rules, this also has exceptions. Using the 'or
>>die' construct has costs (albeit minimal) 
>
> Cost in terms of what? In terms of execution time or memory should be
> negligable except in very extreme cases, in particular because accessing
> the file system  is so expensive on the OS side anyway that you will
> probably have difficulties even measuring the additional cost of die().

I can't say for cartercc, but I have difficulties obviously

perl -wle '
use Benchmark qw|countit cmpthese timethese|;
my $lit = qq{abc\txyz};
my $t = timethese 50_000, {
        die => sub { open my $fh, q|>|, q|/dev/null| or die; },
        maybe => sub { open(my $fh, q|>|, q|/dev/null|) || die; },
        live => sub { open my $fh, q|>|, q|/dev/null|; }, };
cmpthese $t;
'
Benchmark: 
timing 50000 iterations of
 die, live, maybe
...

       die:  4 wallclock secs ( 1.80 usr +  0.91 sys =  2.71 CPU) @
18450.18/s (n=50000)

      live:  3 wallclock secs ( 1.60 usr +  0.99 sys =  2.59 CPU) @
19305.02/s (n=50000)

     maybe:  3 wallclock secs ( 1.72 usr +  0.90 sys =  2.62 CPU) @
19083.97/s (n=50000)

         Rate   die maybe  live
die   18450/s    --   -3%   -4%
maybe 19084/s    3%    --   -1%
live  19305/s    5%    1%    --

         Rate   die maybe  live
die   19608/s    --   -2%   -2%
maybe 20000/s    2%    --   -0%
live  20080/s    2%    0%    --

         Rate   die maybe  live
die   19380/s    --   -1%   -2%
maybe 19531/s    1%    --   -1%
live  19763/s    2%    1%    --

And once I've even had that (though failed to recreate)

        Rate live  die
live 20000/s   --  -1%
die  20161/s   1%   --

*CUT*

-- 
Torvalds' goal for Linux is very simple: World Domination
Stallman's goal for GNU is even simpler: Freedom

8. Perl 'system' Creates Program That Dies When First C Program Dies - Perl