虽然我看到如何让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:
…但我不能说是否确实地回答是否在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); } }