找不到信号处理程序

时间:2017-12-13 21:57:21

标签: perl

由于某些原因,线程似乎无法找到$ SIG {' KILL')信号。我从这里的评论中得到了代码http://www.perlmonks.org/index.pl?node_id=557219这是在Windows上。

use strict;
use warnings;

use threads;

sub test_sub{
    $SIG{'KILL'} = sub { threads->exit(); };
    while(1){}  
}

my $new_thread = threads->create('test_sub');

$new_thread->kill('KILL')->detach();

返回

Signal KILL received in thread 1, but no signal handler set. at test1.pl line 13.
Perl exited with active threads:
        1 running and unjoined
        0 finished and unjoined
        0 running and detached

编辑:看起来我正在使用线程版本' 1.43'。我不知道问题是否存在,但我会尝试更新的版本。

2 个答案:

答案 0 :(得分:2)

这似乎是某种竞争条件,当有更多事情发生时它会起作用。

use warnings;
use strict;
use feature 'say';

use threads;
use threads::shared;

my $thread_handler_on :shared = 0;

sub test_handler {
    say "\tIn thread.";
    $SIG{'KILL'} = sub {
        $thread_handler_on = 1;
        say "\tSet flag, exiting the thread in handler";
        threads->exit();
    };
    sleep 3;
    say "\tSet handler";
    sleep 1;
    say "\tHandler done napping";
}

my $new_thread = threads->create( 'test_handler' );

sleep 1;

say "Sending 'kill' to thread";
$new_thread->kill('KILL')->detach();

sleep 5;

say "Did handler run: $thread_handler_on";

问题中的代码是out of threads个文档(以及detach)。 这打印

        In thread.
Sending 'kill' to thread
        Set flag, exiting the thread in handler
Did handler run: 1

如果主线程中没有sleep,我也会得到报告的行为。

请注意这些"信号"每个Threads signalling

通过内核发送
  

该模块提供的线程信令功能实际上并不通过OS发送信号。它模拟Perl级别的信号,以便在适当的线程中调用信号处理程序。

答案 1 :(得分:2)

只有两种竞争条件可能会导致您观察到的行为:

  • 您在孩子有机会设置信号处理程序之前发送了KILL信号。

    下面,我使用同步来确保在发送信号之前创建信号处理程序。

  • 您在信号处理程序有机会致电threads->exit之前退出该计划。

    为什么人们坚持使用->detach

修正:

use strict;
use warnings;
use feature qw( say );

use threads;
use threads::shared;

sub test_handler {
    say sprintf "[%s %s] Starting thread", time, threads->tid;
    say sprintf "[%s %s] Doing stuff", time, threads->tid;
    sleep 4;
    say sprintf "[%s %s] Done doing stuff", time, threads->tid;
    say sprintf "[%s %s] Exiting thread", time, threads->tid;
}

sub create_thread(&) {
   my ($thread_func) = @_;

   # Reap any threads that might have exited.
   $_->join() for threads->list(threads::joinable);

   my $ready :shared = 0;
   my $thread = async {
      $SIG{KILL} = sub {
         say sprintf "[%s %s] Forcibly exiting thread", time, threads->tid;
         threads->exit();
      };

      # Signal creator that the thread is initialized.
      { lock $ready; $ready = 1; cond_signal($ready); }
      $thread_func->();
   };

   # Wait for the thread to finish initializing.    
   { lock $ready; while (!$ready) { cond_wait($ready); } }
   return $thread;
}

my $thread = create_thread(\&test_handler);

say sprintf "[%s %s] Sending KILL signal", time, threads->tid;
$thread->kill('KILL');

say sprintf "[%s %s] Doing stuff", time, threads->tid;
sleep(2);
say sprintf "[%s %s] Done doing stuff", time, threads->tid;

# Wait for threads to exit.
say sprintf "[%s %s] Waiting for threads to exit", time, threads->tid;
$_->join() for threads->list();
say sprintf "[%s %s] Exiting", time, threads->tid;

输出:

[1513212149 1] Starting thread
[1513212149 1] Doing stuff
[1513212149 0] Sending KILL signal
[1513212149 0] Doing stuff
[1513212151 0] Done doing stuff
[1513212151 0] Waiting for threads to exit
[1513212153 1] Forcibly exiting thread
[1513212153 0] Exiting

重要请注意,信号不会中断sleep。没有发送实际的POSIX信号 [1] (因为您只能将它们发送到进程),因此OS调用不会被中断。相反,Perl会主动检查大多数Perl操作码 [2] 之间是否发送了信号。但这意味着长时间运行的操作码如sleepm//和XS函数调用可以无限期地延迟信号处理程序。

  1. 这很幸运,因为你没有使用POSIX系统。
  2. 前一段时间,它曾经介于每个操作码之间,但检查次数减少了。我认为Perl现在每次声明检查一次。