1

我正在编写一个脚本,其想法是创建线程并同时遍历机器列表并检查内容。看来,当一个线程使用“ssh ......”进入它的单独终端时,它会卡住,我无法杀死它。他们还有一个似乎不起作用的计时器。

这是代码:

sub call_cmd{
    my $host = shift;
    my $cmd = shift;
    my $command = $cmd;
    my $message;

    open( DIR, "$cmd|" ) || die "No cmd: $cmd $!";
    while(<DIR>){
        $message.=$_;
        print "\n $host $message \n";
    }
    close DIR;

    print "I'm here";
}

sub ssh_con($$){

my $host = $_[0]; 
my $cmd = "ssh $host -l $_[1]";
call_cmd($host,$cmd);

}

我得到了 ssh 返回的输出消息,但我从来没有得到下一个打印。

这是创建线程的代码。

foreach(@machines){
    my $_ = threads->create(thread_creation,$_);
    $SIG{ALRM} = sub { $_->kill('ALRM') };
    push(@threads,$_);
}

sub thread_creation(){
    my $host =  $_;

    eval{
        $SIG{ALRM} = sub { die; };
        alarm(5);
        ssh_con($host,"pblue");
        alarm(0);
    }
}

输出 :

 home/pblue> perl tsh.pl

 ssh XXXXX -l pblue

 ssh XXXXX -l pblue

  XXXXX Last login: Mon Sep 30 10:39:01 2013 from ldm052.wdf.sap.corp


  XXXXX Last login: Mon Sep 30 10:39:01 2013 from ldm052.wdf.sap.corp
4

1 回答 1

0

除了您的代码有点奇怪之外,我还遇到了您的问题 - 特别是在 RHEL 5 上的 Perl 5.8.8 中。

似乎存在竞争条件,如果您同时在一个线程中生成两个 ssh 进程,它们就会死锁。我发现的唯一解决方案是您声明的解决方法:

my $ssh_lock : shared;

然后将您的 ssh 作为文件句柄“打开”:

my $ssh_data:
{
    lock ( $ssh_lock );
    open ( my $ssh_data, "|-", "ssh -n $hostname $command" ); 
}
#lock out of scope, so released
while ( <$ssh_data> ) {
    #do something
}

然而,这很可能是新版本的 perl/新操作系统的一个争论点。我当然不能特别可靠地重现它,当我开始使用它时它完全消失了fork()

也就是说 - 你的代码正在做一些相当奇怪的事情。尤其是您正在运行的命令是:

ssh $host -l pblue

这是一个有效的命令,但它会以交互方式启动 ssh - 但因为你是多线程的,所以标准输入和标准输出会做非常奇怪的事情。

您还应该非常小心signals 与多线程 - 由于进程间通信的性质,它不能很好地工作。设置警报信号

对于类似的事情 - 例如通过 ssh 运行命令 - 我已经通过这样的方法取得了一定程度的成功:

#!/usr/bin/perl
use strict;
use warnings;

use threads;
use threads::shared;
use Thread::Queue;

my @servers_to_check = qw ( hostname1 hostname2 hostname3 hostname4 );

my $num_threads = 10;

my $task_q = Thread::Queue->new;
my $ssh_lock : shared;

sub worker_thread {
    my ($command_to_run) = @_;
    while ( my $server = $task_q->dequeue ) {
        my $ssh_results;
        {
            lock($ssh_lock);
            my $pid = open( $ssh_results, "-|",
                "ssh -n $server $command_to_run" );
        }
        while (<$ssh_results>) {
            print;
        }
        close($ssh_results);
    }
}

for ( 1 .. $num_threads ) {
    threads->create( \&worker_thread, "df -k" );
}

$task_q->enqueue(@servers_to_check);
$task_q->end;

foreach my $thr ( threads->list ) {
    $thr->join();
}
于 2015-02-06T21:41:19.017 回答