Catching SIGALRM in a thread

S

Samuel

The following code:

--------------
#!/usr/bin/perl
use threads;

sub run {
my $result = eval q{
local $SIG{ALRM} = sub { die "timed-out\n" };
alarm 2;
sleep 10;
alarm 0;
};
if ($@) {
print "Error: $@\n";
}
}

print "Running in main thread...\n";
run2();
print "Returned. Running in new thread...\n";
my $thread = threads->new(\&run2);
print "Joining...\n";
$thread->join();
print "Done.\n";
--------------

Produces the following output:

--------------
$ perl alrmtst.pl
Running in main thread...
Error: timed-out

Returned. Running in new thread...
Joining...
Alarm clock
$
--------------

Can anyone explain why the SIGALRM is caught in the main thread but
not in the new thread? How do you catch SIGALRM in the second case?

-Samuel
 
S

Samuel

Can anyone explain why the SIGALRM is caught in the main thread but
not in the new thread?

I see now that thread uses in-process threads, not the operating
system's threads, so that explains this behavior to some extent (in
theory, Perl could still have it's own built in signal handler that
disambiguates the alarms, but apparently that is not the case).
How do you catch SIGALRM in the second case?

So how to you do timeouts in threads? I am using a third party module
(Net::Telnet) in a thread that uses SIGALRM for the timeout.
Net::Telnet does provide a way to disable the timeout entirely, but I
don't know how to replace it. Any ideas?

-Samuel
 
X

xhoster

Samuel said:
I see now that thread uses in-process threads, not the operating
system's threads, so that explains this behavior to some extent (in
theory, Perl could still have it's own built in signal handler that
disambiguates the alarms, but apparently that is not the case).


So how to you do timeouts in threads?

I don't. I use forking instead of threads, almost always. And when
I can't, I strongly consider using a different language.
I am using a third party module
(Net::Telnet) in a thread that uses SIGALRM for the timeout.
Net::Telnet does provide a way to disable the timeout entirely, but I
don't know how to replace it. Any ideas?

My Net::Telnet documentation doesn't mention thread safety. I'd take that
as a caution against using Net::Telnet with threads.

Xho
 
G

grocery_stocker

I don't. I use forking instead of threads, almost always. And when
I can't, I strongly consider using a different language.

Mixing threads and signals is like trying to drive in high heels. It
can make for a bad combination if you don't know what you are doing.

With that, I thought about giving some more insight into what was
going on. But the moment I started to think, I had these really
horrible flashbacks to my Mechanical Engineering days. The horrible
flashbacks ceased when I heard the following next door

Girl "F-ck you. I'm tired of this sh-t"
Guy "B-tch, you never told me sh-t"

Then I realized the days of playing "corporate monkey" where long
since behind me. I've found a certain peace and happiness working as
a $11.00/hr Clerk/back-up Janitor in a warehouse despite the fact that
I'm starting to get gray hair.


Chad
 
S

Samuel

I don't. I use forking instead of threads, almost always. And when I
can't, I strongly consider using a different language.

By now, that's pretty much my conclusion. The fact that sharing nested
objects between threads is only possible by making every object and all
of it's attributes thread aware makes things *really* cumbersome. I am
currently looking into the alternatives.
My Net::Telnet documentation doesn't mention thread safety. I'd take
that as a caution against using Net::Telnet with threads.

Yay, another problem! Things could have been going a little bit
smoother... well, at least I have a working prototype.

Thank you for your comment!

-Samuel
 
Z

zentara

By now, that's pretty much my conclusion. The fact that sharing nested
objects between threads is only possible by making every object and all
of it's attributes thread aware makes things *really* cumbersome. I am
currently looking into the alternatives.


Yay, another problem! Things could have been going a little bit
smoother... well, at least I have a working prototype.

Thank you for your comment!

-Samuel

Here is an example I have of an ALARM in a thread. It works for me,
but it may not be what you are looking for. (Honestly I didn't read
this question slowly :) )
My notes indicates threads
and alarms don't work reliably together, but this seems to do OK.

#!/usr/bin/perl
use warnings;
use strict;
use threads;
use threads::shared;

my $waitTime : shared;
my $done : shared;
my $return : shared;
$waitTime = 5;
$done = 0;
$return = '';

my $cmd = './z1';

my $thr = threads->new(\&my_exec_thread, $cmd);

while(1){

if ( $done == 1 ) {
print "Thread completed \n";
print "return= $return\n";
$thr->join;
last;
}elsif ( $done eq 'TIMED OUT' ) {
print "Thread Timed OUT\n";
$thr->join;
last;
}else{next}

}

print "1\n";
######################################################
sub my_exec_thread {
my $cmd = shift;
print ("In thread ".$cmd."\n");

my $maxTime = 5;
my $child_pid;

local $SIG{ALRM} = sub { die "timeout" };

eval {
alarm($maxTime);
unless ($child_pid = fork) {
exec $cmd;
die "could not exec $cmd: $!";
}
wait;
alarm(0);
};

if ($@) {
print $@,"\n";

if ($@ =~ /timeout/) {
local $SIG{'HUP'} = 'IGNORE';
kill('HUP', $child_pid);
return;
}
}

print "end of thread code block\n";
}

__END__

##########################################################
My $cmd ./z1 is simply:

#!/usr/bin/perl
use warnings;
use strict;

my $count = 0;
while(1){
$count++;
print "$count\n";
sleep 1;
}

__END__


zentara
 
X

xhoster

zentara said:
Here is an example I have of an ALARM in a thread. It works for me,
but it may not be what you are looking for.

What OS and what version of Perl are you using?
Your code doesn't work for me. The main program is blown away by
the alarm, without catching it in the SIG{ALRM} and without
clobbering the z1 process, which just keeps on running.

This is perl, v5.8.3 built for x86_64-linux-thread-multi

Thanks,

Xho
 
Z

zentara

What OS and what version of Perl are you using?
Your code doesn't work for me. The main program is blown away by
the alarm, without catching it in the SIG{ALRM} and without
clobbering the z1 process, which just keeps on running.

This is perl, v5.8.3 built for x86_64-linux-thread-multi

Thanks,
Xho

You are right, I'm totally wrong. I'll have to mark that one as
non-working too.
I may have first tested in back in the Perl5.6 days, but it dosn't
work now. :-( Maybe it never worked, but I was too dumb to
notice. :)
Sorry for the confusion.

It seems that setting alarm in the thread will kill the main thread.
Try this, where I set the alarm callback in main, it works. So you
should be able to work around it. Of course if you want to have separate
alarms in multiple threads, you are SOL. The only thing you can do in
that case, is have secondary timer threads instead of alarm, OR use
an event loop system in your main thread, that can timeout the thread
by running it's own timer.
To be honest, I never even use alarm anymore, I setup my own timers,
since I generally use Tk, or Gtk2. (POE would work too).
Gtk2's GLib will setup timers even in non-gui programs, as will POE.
Tk has to be a GUI.

#!/usr/bin/perl
use warnings;
use strict;
use threads;
use threads::shared;

# ALARM DOSN"T WORK WELL IN THREADS

my $waitTime : shared;
my $done : shared;
my $child_pid : shared;
$waitTime = 5;
$done = 0;

my $cmd = './z1';
my $thr = threads->new(\&my_exec_thread, $cmd);

$SIG{ALRM} = sub { warn "thread timeout\n";
kill 9, "$child_pid\n";
};

while(1){

if ( $done == 1 ) {
print "Thread completed \n";
$thr->join;
last;
}elsif ( $done eq 'TIMED OUT' ) {
print "Thread Timed OUT\n";
$thr->join;
last;
}else{next}

}

print "1\n";
######################################################


sub my_exec_thread {
my $cmd = shift;
print ("In thread ".$cmd."\n");

###########################################
# will kill it all, even main thread with message ALARM CLOCK
#$SIG{ALRM} = sub { warn "thread timeout\n";
# kill 9, "$child_pid\n";
# };
############################################

eval {
alarm($waitTime);
unless ($child_pid = fork) {
exec $cmd;
die "could not exec $cmd: $!";
}
print "pid->$child_pid\n";
wait;
alarm(0);
};

print "--------- $@\n";
print "end of thread code block , main lives on\n";
}
__END__


zentara
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top