Reputation: 12452
use threads;
use threads::shared;
use Term::ReadKey;
sub input_worker {
local $SIG{'KILL'} = sub { threads->exit(0); return;};
while (1) {
if (defined(my $char = ReadKey 0, *STDIN)) {
print "$char";
}
}
return;
} ## end sub input_worker
my $in_thr = threads->create(\&input_worker);
sleep 5;
my $rc = $in_thr->kill('KILL')->join();
print "$rc\n";
This program wont exit by itself and just hangs. It will only exit after pressing "enter"
How can i make it so that it will exit by itself after 'kill' is signaled
P.S. I dont want to use detach();
Upvotes: 1
Views: 112
Reputation: 53478
Mixing signals and threads is a bit of a challenge, simply because $thread->kill
doesn't actually use real signals (since signals are sent to processes, not threads). Which is just as well, because if it did, SIGKILL
can break things.
Even when talking about 'normal' signals - you will have slightly unexpected behaviour, because of perl's handling of them See: perlipc
. It's not impossible to use, but you need to be aware of the caveats involved.
But the root of the problem is - that the signal is handled safely, which means perl waits until a suitable moment to process it. It will not do this during a 'read' operation, so the signal processing will get deferred.
I think likely what is happening here is your ReadKey
is not a nonblocking operation like you think it is. With reference to the Term::ReadKey
manpage
ReadKey MODE [, Filehandle] Takes an integer argument, which can currently be one of the following values:
0 Perform a normal read using getc
-1 Perform a non-blocked read
>0 Perform a timed read
So what it does instead is - starts reading from STDIN
, and blocks (ignoring signals) until you press enter. At which point it runs your signal handler.
Given what you're trying to do here - I would suggest you don't want to use signals at all, and instead - just use a shared variable.
Something like this:
use threads;
use threads::shared;
use Term::ReadKey;
my $done : shared;
sub input_worker {
while ( not $done ) {
if ( defined( my $char = ReadKey( -1, *STDIN ) ) ) {
print "$char";
}
}
return;
} ## end sub input_worker
my $in_thr = threads->create( \&input_worker );
sleep 10;
$done++;
my $rc = $in_thr->join();
print "$rc\n";
Will terminate after the timeout, and because it's doing nonblocking reads, it'll bail out on time, without input. You should note though - this thread is going to be 'spinning' looping rapidly waiting to see if input has been pressed - so it's not very CPU efficient. (a small delay in the cycle helps immensely there, say 0.1s).
Upvotes: 5