从Perl线程运行bash脚本

时间:2017-08-09 18:40:51

标签: multithreading bash perl

我的脚本应该有n个子程序( my_proc )同时运行,每个子程序运行bash脚本,一个子程序( check_procs )检查子程序是否已完成。

use strict;
use threads;
use threads::shared;

my %proc_status :shared;
my %thr;

foreach my $i (1,2,3,4) {
    $proc_status{$i}=0;
}

sub my_proc {
    my $arg=shift(@_);
    while (1) {
         sleep(2);
         print "Proc $arg Started\n";
         #exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec");   # case 1
         #`sleep_for_10_sec.bash &`;                                        # case 2      

         print "Proc $arg Finished\n";
         {
         lock(%proc_status);
         $proc_status{$arg}=1;
         }
    }
}

sub check_procs {
    my $all_finished;
    while (! $all_finished) {
            sleep 5;
            print "CHECK: \n";
            $all_finished=1;
            foreach my $num (1,2,3,4) {
                    if ($proc_status{$num} == 1) {
                            print "CHECK: procedure $num has finished\n";
                    } else {
                        $all_finished=0;
                    }
            }
    }
    print "All jobs finished\n";
}

foreach my $num (1,2,3,4) {
    $thr{"$num"} = new threads \&my_proc,$num;
}

my $thr_check= new threads \&check_procs;
$thr_check->join();

这是sleep_for_10_sec.bash

ls
# bunch of other stuff 
sleep 10
echo "finished sleep"

我不希望 my_proc sub等待“sleep_for_10_sec.bash”命令执行,浏览后我发现 #case1 # case2 应该有效,但它们都失败了。

#case1的输出:

 Proc 1 Started
 [ls result]
 finsihed sleep

#case2的输出:

Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
CHECK:
CHECK:
Proc 4 Finished
Proc 2 Finished
Proc 3 Finished
Proc 1 Finished
Proc 3 Started
Proc 1 Started
Proc 2 Started
Proc 4 Started
CHECK:
CHECK: procedure 1 has finished
CHECK: procedure 2 has finished
CHECK: procedure 3 has finished
CHECK: procedure 4 has finished

但我期待这样的事情:

 Proc 1 Started
 Proc 2 Started
 Proc 3 Started
 Proc 4 Started
 Proc 1 Finished
 Proc 1 Started
 Proc 3 Finished
 Proc 3 Started
 Proc 4 Finished
 Proc 4 Started
 Proc 2 Finished
 Proc 2 Started
 CHECK:
 CHECK:
 CHECK:
 CHECK: procedure 1 has finished
 CHECK: procedure 2 has finished
 CHECK: procedure 3 has finished
 CHECK: procedure 4 has finished

实际上,如果将输出重定向到“> log”,我会得到想要的结果,但无论如何:

 Proc 1 Started
 Proc 2 Started
 Proc 3 Started
 Proc 4 Started

等待“sleep_for_10_sec.bash”完成。

这是我第一个使用“thread”和“exec”的项目,有人可以帮我吗?

2 个答案:

答案 0 :(得分:1)

exec不应与线程结合使用。 exec在当前进程中启动一个新程序,因此当您从一个线程调用exec时,线程正在执行的程序将消失。由于线程没有要执行的程序,exec也会杀死线程。

我不清楚为什么案例2不起作用(编辑:见下面的ikegami评论)。我认为它会启动进程,在后台运行它,并允许Perl线程立即继续。它似乎没有这样做,但这段代码将:

system("/bin/bash sleep_for_10_sec.bash &");        # case 3

答案 1 :(得分:1)

  

Object get() { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Object> response = executor.submit(() -> { return execute(); }); executor.shutdown(); executor.awaitTermination(10, TimeUnit.SECONDS); if (executor.isTerminated()) { return response.get(); } executor.shutdownNow(); return get(); }

exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec"); # case 1用另一个程序替换当前进程中运行的程序。同时,现有的线程被终止(因为他们想要执行的程序不再存在),取而代之的是执行新程序的单个线程。

这意味着exec永远不会返回(错误除外)。线程或没有线程,exec不是您想要的,因为您不希望您的程序停止运行。

  

但我希望这样的事情:

您是否确定要每两秒启动一次exec 4次(意味着您最多可以同时运行20个),因为您想要的输出显示?

您确定不关心sleep_for_10_sec.bash是否完成,因为您想要的输出显示?

如果是这样,你为什么要使用线程呢?您可以简单地使用以下内容:

sleep_for_10_sec.bash

我想你想要

sub start {
   my $num = shift;
   say "Proc $num Started";
   system('bash -c sleep_for_10_sec.bash &');
   say "Proc $num Finished";
}

for my $pass (1..2) {
   start($_) for 1..4;
   sleep 2;
   start($_) for 1..4;
   sleep 2;
   start($_) for 1..4;
   sleep 1;
   if ($pass == 1) {
      say "CHECK:";
   } else {
      say "CHECK: procedure $_ has finished" for 1..4;
   }
}