Perl用bash中的线程陷阱Ctrl-C

虽然我看到如何让Perl在bash中捕获Ctrl-C(sigint) 我迷失在为什么会失败与线程; 我正在尝试下面的脚本:

#!/usr/bin/env perl use threads; use threads::shared; # for shared variables my $cnt :shared = 0; sub counter() { while (1) { $cnt++; print "thread: $cnt \n"; sleep 1; } } sub finisher{ ### Thread exit! ... print "IIII"; threads->exit(); die; }; # any of these will cause stop of reaction to Ctrl-C $SIG{INT} = \&finisher; $SIG{INT} = sub {print "EEE\n" ;} ; $SIG{INT} = 'IGNORE'; # setting to DEFAULT, brings usual behavior back #~ $SIG{INT} = 'DEFAULT'; my $mthr = threads->create(\&counter); $mthr->join(); 

…一旦SIGINT处理程序被设置为默认值( 其中Ctrl-C导致退出 )以外,基本上会导致脚本停止在Ctrl-C上作出反应:

 $ ./test.pl thread: 1 ^Cthread: 2 ^C^Cthread: 3 ^C^C^C^Cthread: 4 thread: 5 thread: 6 thread: 7 thread: 8 Terminated 

…我必须sudo killall perl才能结束脚本。

在这些链接上有一些线程和Ctrl-C:

  • 发送sig INT(控制C)到线程 – Dev Shed
  • 解决:这是一个Perl线程的错误? – Perl僧侣
  • 我们如何捕获CTRL ^ C – Perl僧侣
  • 信号处理器是否应该像这样工作?

…但我不能说是否确实地回答是否在bash下“捕获”perl下的Ctrl-C是绝对不可能的?

预先感谢任何答案,
干杯!


好吧,我想我知道了( 但是我离开了前面的条目(下面)以供参考…

诀窍结果是,从主要的SIGINT处理程序,必须通过kill信号的线程 – 然后线程还需要有一个单独的SIGINT处理程序(从OP中的第一个链接); 而不是只是join() ,你需要在@ikegami的答案中使用代码:

 #!/usr/bin/env perl use threads; use threads::shared; # for shared variables my $cnt :shared = 0; my $toexit :shared = 0; sub counter() { $SIG{'INT'} = sub { print "Thread exit\n"; threads->exit(); }; my $lexit = 0; while (not($lexit)) { { lock($toexit); $lexit = $toexit; } $cnt++; print "thread: $cnt \n"; sleep 1; } print "out\n"; } my $mthr; sub finisher{ { lock($toexit); $toexit = 1; } $mthr->kill('INT'); }; $SIG{INT} = \&finisher; $mthr = threads->create(\&counter); print "prejoin\n"; #~ $mthr->join(); while (threads->list()) { my @joinable = threads->list(threads::joinable); if (@joinable) { $_->join for @joinable; } else { sleep(0.050); } } print "postjoin\n"; 

我可能会用$toexit ,但至less现在是这样的结果:

 $ ./test.pl prejoin thread: 1 thread: 2 thread: 3 ^CThread exit postjoin 

非常感谢所有的解决scheme:)
干杯!


感谢@mob对PERL_SIGNALS的build议, 注意 unsafe注意, Perl 5.14不允许$ ENV {'PERL_SIGNALS'}的“内部”设置 ),我在某处 – 现在检测到Ctrl-C,但是它终止与段错误,或与错误:

 #!/usr/bin/env perl use threads; use threads::shared; # for shared variables my $cnt :shared = 0; my $toexit :shared = 0; sub counter() { my $lexit = 0; while (not($lexit)) { { lock($toexit); $lexit = $toexit; } $cnt++; print "thread: $cnt \n"; sleep 1; } print "out\n"; #~ threads->detach(); # Thread 1 terminated abnormally: Cannot detach a joined thread #~ exit; } my $mthr; # [http://code.activestate.com/lists/perl5-porters/164923/ [perl #92246] Perl 5.14 does not allow "internal" setting of $ENV ...] sub finisher{ ### Thread exit! ... #~ print "IIII"; # anything here results with: Perl exited with active threads: #~ threads->exit(); #~ threads->join(); #~ $mthr->exit(); #~ $mthr->join(); #~ $mthr->detach(); #~ $mthr->kill(); #~ threads->exit() if threads->can('exit'); # Thread friendly #~ die; { lock($toexit); $toexit = 1; } #~ threads->join(); # }; # any of these will cause stop of reaction to Ctrl-C $SIG{INT} = \&finisher; #~ $SIG{INT} = sub {print "EEE\n" ; die; } ; #~ $SIG{INT} = 'IGNORE'; # setting to DEFAULT, brings usual behavior back #~ $SIG{INT} = 'DEFAULT'; $mthr = threads->create(\&counter); print "prejoin\n"; $mthr->join(); print "postjoin\n"; 

通过上面的注释,该代码会对以下内容做出反应:

 $ PERL_SIGNALS="unsafe" ./testloop06.pl prejoin thread: 1 thread: 2 thread: 3 ^Cthread: 4 out Segmentation fault 

结果是一样的,如果我添加以下使用Perl :: Signals :: Unsafe :

 $mthr = threads->create(\&counter); UNSAFE_SIGNALS { $mthr->join(); }; 

几乎在那里,希望有人可以在…钟声:)

信号处理程序仅在Perl操作码之间调用。 你的代码被封锁在$mthr->join(); ,所以它永远不会处理信号。

可能的方案

 use Time::HiRes qw( sleep ); # Interruptable << $_->join() for threads->list; >> while (threads->list()) { my @joinable = threads->list(threads::joinable); if (@joinable) { $_->join for @joinable; } else { sleep(0.050); } }