我已经使用Perl Threads建立了一个多线程应用程序,并且正在尝试检测线程内的超时(该线程应该经过几个系统调用,这些超时可能会超时,我需要知道它何时停止)。
我尝试使用alarm(),并遇到了线程0(而不是触发警报的线程)接收到的警报信号的详细记录问题。所以我转向使用Alarm :: Concurrent。
use threads ('yield',
'stack_size' => 64*4096,
'exit' => 'threads_only',
'stringify');
use Alarm::Concurrent qw(setalarm clearalarm);
threads->create(\&MyThreadFunc,1);
threads->create(\&MyThreadFunc,1);
threads->create(\&MyThreadFunc,5);
threads->create(\&MyThreadFunc,5);
sub MyThreadFunc {
my $result = "Never Ran";
my $timeToSleep = $_[0];
my $tid = threads->tid();
eval {
setalarm 3, sub { die "Timedout\n" };
sleep ($timeToSleep);
clearalarm;
$result = "TID $tid EXITED\n";
};
if ($@ eq "Timedout\n")
{
$result = "TID $tid TIMED OUT\n";
}
elsif ($@)
{
$result = "$@";
}
print "Thread returning $result";
return $result;
}
while (scalar threads::list(threads::running))
{
foreach my $thread (threads->list(threads::joinable)) { $thread->join(); }
}
我期望的是:
我希望线程TID 1和2正常退出,线程3和4退出TimedOut路径(因为将调用警报,并且eval()会捕获到“ Timedout \ n”。) EXITD路径。
Thread returning TID 1 EXITED
Thread returning TID 2 EXITED
Thread returning TID 4 EXITED
Thread returning TID 3 EXITED
答案 0 :(得分:1)
信号被脚本的主线程(线程ID = 0)捕获。 因此,出于其他目的在线程中设置信号处理程序 比上面记录的THREAD SIGNALING无法完成
如果尝试在线程中捕获SIGALRM,则尤其如此。至 处理线程中的警报,在主线程中设置信号处理程序, 然后使用THREAD SIGNALING将信号中继到线程:
my $thr = threads->create(sub { threads->yield(); eval { $SIG{ALRM} = sub { die("Timeout\n"); }; alarm(10); ... # Do work here alarm(0); }; if ($@ =~ /Timeout/) { warn("Task in thread timed out\n"); } }; # Set signal handler to relay SIGALRM to thread $SIG{ALRM} = sub { $thr->kill('ALRM') }; ... # Main thread continues working
以下是如何使用它的示例:
use threads ('yield',
'stack_size' => 64*4096,
'exit' => 'threads_only',
'stringify');
use feature qw(say);
use strict;
use warnings;
use Alarm::Concurrent qw(setalarm clearalarm);
{
create_thread(sleep_time => 1, timeout => 3);
create_thread(sleep_time => 1, timeout => 3);
create_thread(sleep_time => 5, timeout => 3);
create_thread(sleep_time => 5, timeout => 3);
while (scalar threads::list(threads::running)) {
foreach my $thread (threads->list(threads::joinable)) { $thread->join(); }
}
}
sub create_thread {
my (%options) = @_;
my $thr = threads->create(\&MyThreadFunc, $options{sleep_time});
setalarm $options{timeout}, sub {
$thr->kill('SIGTERM');
};
}
sub MyThreadFunc {
my $result = "Never Ran";
my $timeToSleep = $_[0];
my $tid = threads->tid();
eval {
local $SIG{TERM} = sub { die "Timedout\n" };
sleep ($timeToSleep);
$result = "TID $tid EXITED\n";
};
if ($@ eq "Timedout\n") {
$result = "TID $tid TIMED OUT\n";
}
elsif ($@) {
$result = "$@";
}
print "Thread returning $result";
return $result;
}
输出:
Thread returning TID 1 EXITED
Thread returning TID 2 EXITED
Thread returning TID 3 TIMED OUT
Thread returning TID 4 TIMED OUT