它在系统命令中的超时线程

时间:2012-05-11 05:53:27

标签: multithreading perl interrupt-handling

我有一个看似简单的问题。我需要执行一系列的 系统命令(使用反引号)并行。

除了以下代码之外,以下代码已被删除 证明我的问题:

#!/usr/bin/perl -w 
use strict; 
use threads; 
use POSIX; 
my @threads = (); 
sub timeout { 
  print "TIMEOUT\n"; 
  foreach my $thread (@threads) { 
    $thread->kill("ALRM") if $thread->is_running(); 
  } 
} 

POSIX::sigaction(SIGALRM, POSIX::SigAction->new(\&timeout)); 
alarm(2); 
sub threadsub { 
  sub handletimeout { 
    print "KILL\n"; 
    threads->exit(1); 
  } 
  POSIX::sigaction(SIGALRM, POSIX::SigAction->new(\&handletimeout)); 
  # while(1) { sleep(1); } 
  return `sleep 10`; 
} 

for(my $i=0; $i < 10; $i++) { 
  push(@threads, thread->create(\&threadsub)); 
} 

foreach my $thread (@threads) { 
  my $res = $thread->join(); 
}

现在,问题是从不发送到线程的ALRM信号 在系统调用中阻塞线程时捕获。如果你取消注释 while循环信号按预期捕获。 我如何使这项工作,所以即使我能够超时我的线程 他们被困在系统命令中?

谢谢,

卡斯帕

1 个答案:

答案 0 :(得分:0)

来自 man threads

   Unsafe signals
       Since Perl 5.8.0, signals have been made safer in Perl by postponing their handling until the interpreter is in a safe state.  See "Safe
       Signals" in perl58delta and "Deferred Signals (Safe Signals)" in perlipc for more details.

       Safe signals is the default behavior, and the old, immediate, unsafe signalling behavior is only in effect in the following situations:

       ?   Perl has been built with "PERL_OLD_SIGNALS" (see "perl -V").

       ?   The environment variable "PERL_SIGNALS" is set to "unsafe" (see "PERL_SIGNALS" in perlrun).

       ?   The module Perl::Unsafe::Signals is used.

       If unsafe signals is in effect, then signal handling is not thread-safe, and the "->kill()" signalling method cannot be used.

该效果表明信号将被推迟到perl处于非安全状态。如果我们切换到'unsafe-signals'程序终止,消息无法在threads.pl 处发出没有安全信号的线程。请检查系统中是否有不安全信号。虽然它有效,但不安全。建议迁移到流程。以下代码应该可以为您提供所需的结果。

use strict;
use POSIX;

my $pid=fork();

sub timeout {
  print "TIMEOUT\n";
  kill SIGALRM,$pid;
}

if( $pid ) { ## parent
    alarm(2);
    POSIX::sigaction(SIGALRM, POSIX::SigAction->new(\&timeout));
    waitpid $pid,0;
} else { ## child
    sub handletimeout {
        print "SIGALRM child\n";
        exit(1);
    }
    POSIX::sigaction(SIGALRM, POSIX::SigAction->new(\&handletimeout));
    `sleep 10`;
    print "child normal exit";
}