2012-05-11 79 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"; 
}