2012-05-11 80 views
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循环信号按预期捕获。 如何使这项工作,使我能够超时我的线程,即使 他们卡在系统命令?

感谢,

卡斯帕

+0

作为解决方法我现在已经成功地使用了一个来自threads :: shared的条件变量。然后,我可以在主线程中保持中断处理,并在cond_wait而不是$ thread-> join()中使用此块。在超时时间之后,我使用分离功能杀死主线程中的线程。我仍然希望上面的代码工作艰难。 –

回答

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是在非安全状态。如果我们切换到'不安全信号'程序终止并显示消息不能在没有安全信号的情况下通过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"; 
}