从 Perl 线程运行 bash 脚本



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

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 Startedn";
#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 Finishedn";
{
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 finishedn";
} else {
$all_finished=0;
}
}
}
print "All jobs finishedn";
}
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子等待"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

实际上,在将输出重定向到">日志"的情况下,我得到了想要的结果,但无论如何之后:

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

它等待"sleep_for_10_sec.bash"完成。

这是我使用"线程"和"exec"的第一个项目,有人可以帮助我吗?

exec

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

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

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

exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec"); # case 1

exec将当前进程中运行的程序替换为另一个程序。同时,现有线程被终止(因为它们要执行的程序不再存在(,替换为执行新程序的单个线程。

这意味着exec永远不会返回(除非出错(。线程或无线程,exec不是你想要的,因为你不希望你的程序停止运行。


但我期待这样的东西:

您是否确定要按照所需的输出指示每两秒启动sleep_for_10_sec.bash4 次(这意味着您一次最多可以运行 20 次(?

您确定您不在乎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;
}
}

我想你想要

use threads;
use Thread::Queue qw( );  # 3.01+
use constant NUM_WORKERS => 4;
sub worker {
my $num = shift;
say "Job $num Startedn";
system("sleep_for_10_sec.bash");  # Make sure starts with #! and is executable.
say "Job $num Finishedn";
}
{
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
while (defined( my $job = $q->dequeue() )) {
worker($job);
}
}    
$q->enqueue(1..4, 1..4);
$q->end();
$_->join() for threads->list;
}

最新更新