2014-04-08 5 views
1

많은 원격 호스트에서 명령을 실행하는 상당히 큰 프로그램을 작성했지만 심각한 문제가 발생했습니다.이를 수정하는 방법을 모르겠습니다.Net :: OpenSSH와 스레드를 결합 할 때 신호 문제가 발생했습니다.

주위에 노력을 많이 후, 나는 내 컴퓨터에 신뢰성 문제를 재현하기위한 최소 코드를 추출 할 수 있었다 : 사전 설치된 펄 5.10으로

use warnings; 
use strict; 
use threads; 
use threads::shared; 
use Data::Dumper; 
use POSIX ":sys_wait_h"; 
use Net::OpenSSH; 
use Time::HiRes qw(usleep); 

my @LIST=qw(host038b host039a host039b host040a host040b host041a host041b host043a 
    host043b host044a host044b host045a host045b host046a host046b host047a host047b host049a 
    host049b host050a host050b host054a host054b host055a host055b host056a host056b host057a 
    host057b host058a host059a host059b host060a host060b host062a host062b host063a host068a 
    host068b host069a host069b host071a host071b host072a host073a host073b host075a host075b 
    host078a host078b host082a host082b host087a host087b host089a host089b host090a host090b 
    host091a host091b host092a host092b host096a host096b host097a host097b host098a host099a 
    host099b host100a); 
my ($SSH, $CPID, %PIDS, @DONE); 

sub _testthread { 
    # Read stdout pipe 
    my $SCROUT=shift; 
    while (<$SCROUT>) { 
    print $_;    # I normally write that to a logfile 
    } 
    return (0); 
} 

foreach (@LIST) { 
$SSH->{$_}=Net::OpenSSH->new($_,  async => 1, 
           master_opts => [ -o => "PasswordAuthentication=no"]); 
} 

$SIG{CHLD} = sub { my $WPID; 
      push (@DONE, { 'PID' => $WPID, 'RC' => $?, 'ERR' => $!}) while (($WPID = waitpid(-1, WNOHANG)) > 0) }; 

foreach (@LIST) { 
    my ($SCRFH, $SCROUT, undef, $CPID) = $SSH->{$_}->open_ex({stdin_pipe => 1, 
                  stdout_pipe => 1}, '/bin/bash -s'); 
    $PIDS{$CPID}='ACTIVE'; 
    threads->new('_testthread', $SCROUT); 
    print $SCRFH "sleep 2\n"; 
    print $SCRFH "echo test `hostname`\n"; 
    print $SCRFH "exit 0\n"; 
    close $SCRFH; 
    usleep 10000; 
} 

while (grep(/^ACTIVE/, values(%PIDS)) > 0) { 
    print Dumper \%PIDS; 
    while (@DONE) { 
    my $DONE = shift (@DONE); 
    $PIDS{$DONE->{PID}}='DONE'; 
    } 
    sleep 1; 
} 

$_->join foreach (threads->list); 

이는 경우에도 대부분의 시간을 세그먼테이션 폴트 (segfault) open_ex 출력을 파일 설명자로 재구성하는 좀 더 복잡한 구조를 취합니다. 새로 컴파일 된 perl 5.18.2에서이 스크립트는 대부분 SIG {CHLD}를받지 못하기 때문에 무기한으로 정지합니다. 안전 신호를 사용하고 있지만 (이해할 수있는 한).

문제를 재현하려면 다음 사항이 필요 것 같다 :

  • (NET : OpenSSH의 방법 또는 파생) open_ex시키는 @LIST
  • 호스트의 충분한 수의 포크
  • SIG위한 신호 처리기를 사용하여 스레드
  • 에 그 포크의 STDOUT 파일 핸들을주고 {CHLD} 내 양방향으로

이 구조를 사용하는 gger 프로그램은 대부분 사용할 수 없기 때문에 누군가가 해결책을 찾도록 도와 줄 수 있다면 매우 행복 할 것입니다.

감사, 인사,

Mazze

+0

5.18의 문제점은 'SIGCHLD'신호가 모든 스레드에 도달 할 수 있다고 생각합니다. 따라서 여러분의 스크립트는'waitpid' 호출을'@ DONE' 클론으로 나눠서 결과를 보냅니다. 5.10과 관련하여 segfault는 perl 또는 threads 모듈의 버그를 나타냅니다. – salva

+1

@DONE에 "threads :: shared"를 사용하면 문제가 완화 될 것이라고 생각하십니까? – Mazze

+0

나는 지금 그것을 시험해 보았다. 그리고 지금까지 작동하는 것 같다. – Mazze

답변

1

당신은 신호와 스레드를 혼합하려고하는, 그것은 항상 좋은 생각이 될 것입니다. 해결책은 단순히 스레드 사용을 중지하는 것입니다. 당신이하는 일은 무엇이든 다른 방식으로 더 좋게 진행될 수 있습니다.

이러한 동시 IO 작업을 수행하기 위해 일종의 비동기식/이벤트 기반 IO 시스템을 고려해보십시오.

관련 문제