Threaded perl and signal handlers

2019-05-14 02:08发布

问题:

I am using the Thread::Pool module in perl to parallelize some perl code. This process takes a while and occasionally I will kill it from the command line with a SIGINT. Doing so causes the program to end abruptly, as I expected. This leaves some messy temporary files around, so I'd like to install a signal handler. I did this:

sub INT_Handler{
    #clean up code
    exit(1);
}
$SIG{'INT'} = 'INT_handler';

before creating the thread pool and starting the threads. Now when I send the SIGINT, the worker threads that are running die, but the pool promptly launches another set workers to handle the next set of jobs and continues running. Why doesn't the call to exit in the signal handler exit the main thread? What do I need to stop the process from running?

Edited in response to mob's comment

** Further edit **

Here is an example I wrote up.

use Thread::Pool;

sub INT_handler{
    print "Handler\n";
    exit(1);
}

$SIG{'INT'}='INT_handler';

sub f{
    print "Started a thread " . rand(10000) . "\n";
    sleep(10);
}

my $pool;
my $submit = \&f;

if (0){
 $pool = Thread::Pool->new({do=>'f', workers=>5});
  $submit = sub{ $pool->job; }
}

for (my $i = 0; $i < 100; $i++){ $submit->(); }

$pool->shutdown if defined $pool;

with 0, I see the expected result

h:57 Sep 15 16:15:19> perl tp.pl
Started a thread 3224.83224635111
Handler

but with 1, this happens

h:57 Sep 15 16:14:56> perl tp.pl
Started a thread 5034.63673711853
Started a thread 9300.99967009486
Started a thread 1394.45532885478
Started a thread 3356.0428193687
Started a thread 1424.4741558014

etc and the handler doesn't get entered and the process continues running. I had to kill the process with a signal other than SIGINT. Without the handler, both cases simply exit when passed a SIGINT.

回答1:

This is more a hint rather than a definitive answer, but it appears your main thread is never in the "safe" state to run the signal handler. It does work when you enable Perl's unsafe signals:

PERL_SIGNALS=unsafe perl tp.pl

See perlipc for more information on safe and unsafe signals -- maybe it will lead you in the right direction to implement it with safe signals (as it probably should be).


(update by mob) Building on Michal's original insight, this workaround with Perl::Unsafe::Signals also gets the handler to work as you'd expect

use Perl::Unsafe::Signals;
...
UNSAFE_SIGNALS {
    $pool->shutdown if defined $pool;
};

So clearly it is something about Perl's safe signalling mechanism that is interfering with the signal on its way to the handler. I wonder if this would be fixed by putting an UNSAFE_SIGNALS { ... } block inside of Thread::Pool::shutdown. Either way, I would file a bug report about this.