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によってexitが発生します)、基本的にスクリプトは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スレッドのバグですか?-パールモンク
- CTRL^Cをキャプチャするにはどうすればよいですか-PerlMonks
- シグナルハンドラーはこのように機能するはずですか?
...しかし、bashのperlの下でCtrl-Cを「キャプチャ」することが絶対に不可能かどうかが決定的に答えられるかどうかはわかりません。
よろしくお願いします、
乾杯!
わかりました、私はそれを手に入れたと思います(しかし、私は参考のために前のエントリ(以下)を残しています...)
秘訣は、メインのSIGINTハンドラーから、kill
-を介してスレッドにシグナルを送信する必要があることです。次に、スレッドには(OPの最初のリンクからの)別のSIGINTハンドラーも必要です。そして、単にの代わりに、@ikegamiによる回答join()
のコードを使用する必要があります。
#!/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
が、少なくとも今これは結果です:
$ ./test.pl
prejoin
thread: 1
thread: 2
thread: 3
^CThread exit
postjoin
解決策をありがとうございました:)
乾杯!
PERL_SIGNALS
@mobによるtoの提案のおかげでunsafe
(Perl5.14は$ENV {'PERL_SIGNALS'}の「内部」設定を許可していません)、どこかに到達しています-現在Ctrl-Cが検出されています-しかし、どちらかで終了しますsegfault、またはエラーあり:
#!/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();
};
ほとんどそこに、うまくいけば誰かがチャイムを鳴らすことができます... :)