2012-06-13 32 views
2

我有一個調用其他幾個函數的函數,例如這個非分叉Perl超時方法是否安全?

sub do_work { 
    send_mail(); 
    send_soap_envelope(); 
    send_rpc(); 
} 

被調用的函數可能會掛起,所以我想在超時後停止它們。我想避免分叉,因爲在我的上下文中它很昂貴(例如,在每個分支之後需要重新創建數據庫句柄)。我已經想出以下方案:

sub timeout { 
    my ($code) = @_; 
    eval { 
     alarm 2; 
     local $SIG{ALRM} = sub { die 'timeout' }; 
     &$code; 
     alarm 0; 
    }; 
    # handling of [email protected] eq 'timeout' removed for brevity 
} 

sub do_work { 
    timeout \&send_mail; 
    timeout \&send_soap_envelope; 
    timeout \&send_rpc; 
}; 

timeout()函數(在本例中硬編碼到2秒的超時)使用eval塊作爲中止使用die有效載荷功能的執行的裝置。

這在我的測試場景中工作正常,但我對如果die在Perl解釋器不處於「安全狀態」時中斷有效負載功能會發生什麼感到不安。而它正在處理一個XS子程序。我的直覺是對的嗎?

回答

5

從5.8.1開始,Perl使用「安全信號處理」。它不會將信號處理程序提供給系統,而是提供安全的信號處理程序。這個安全的信號處理程序簡單地注意到一個信號被接收並返回。在執行Perl操作碼之間,解釋器檢查是否收到任何信號,並在有信號處理程序的情況下調用您的信號處理程序。

這意味着信號將不會在長時間運行的過程中得到處理,例如長XS呼叫或長正則匹配。信號中斷大部分的系統調用,所以信號進來從那以後,如果你是在一個阻塞系統調用的中間(如sleepread等)

alarm(2); 
my $s = time; 
$SIG{ALRM} = sub { 
    my $e = time; 
    print $e-$s, "\n"; # 6, not 2. 
}; 
('a' x 25) =~ /a*a*a*a*a*a*a*a*a*(?:b|c)/; 

* —爲了你的信號處理程序將被簡稱爲爲了加速程序,現在檢查頻率較低,但你不應該注意到其中的差異。

+0

看起來像你心靈感應地將缺少的「警報0」線路傳送到我的頭上。在你的答案出現之前,我自己就想起了。不管怎麼說,還是要謝謝你。 –

+0

新增示例。如果結束得太快,使'25'略大。 – ikegami

0

好了,現在我看到perldoc -f alarm提到我的確切使用情況:

如果你想使用「警報」超時系統調用,你需要使用「EVAL」 /「死「對。

(舉例碼,然後在那裏。)

1

這不是相當安全的,因爲它要求alarm()它安裝SIGALRM處理程序之前。交換local $SIG{ALRM}alarm行,它應該有很大的改進。