1

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

除了演示我的问题之外,下面的代码已经被剥夺了任何有意义的东西:

#!/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 循环,则会按预期捕获信号。我该如何进行这项工作,以便即使线程卡在系统命令中,我也可以使线程超时?

谢谢,

卡斯帕

4

1 回答 1

0

人线程

   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 处出现消息 Cannot signal threads without safe signals。请检查不安全信号是否在您的系统中工作。虽然它有效,但它是不安全的。建议迁移到进程。下面的代码应该会给你想要的结果。

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";
}
于 2012-05-11T07:55:20.090 回答