Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何使waitpid阻塞循环_Perl_Optimization_Waitpid - Fatal编程技术网

Perl 如何使waitpid阻塞循环

Perl 如何使waitpid阻塞循环,perl,optimization,waitpid,Perl,Optimization,Waitpid,下面的代码运行2个孩子,他们将等待10秒并终止。家长坐在一个圈中,等待孩子们终止: #!/usr/bin/perl use strict; use warnings; use POSIX ":sys_wait_h"; sub func # {{{ { my $i = shift; print "$i started\n"; $| = 1; sleep(10); print "$i finished\n"; } # }}} my $

下面的代码运行2个孩子,他们将等待10秒并终止。家长坐在一个圈中,等待孩子们终止:

#!/usr/bin/perl

use strict;
use warnings;
use POSIX ":sys_wait_h";

sub func
# {{{
{
      my $i = shift;
      print "$i started\n";
      $| = 1;
      sleep(10);
      print "$i finished\n";
}
# }}}

my $n = 2;
my @children_pids;

for (my $i = 0; $i < $n; $i++) {
      if ((my $pid = fork()) == 0) {
            func($i);
            exit(0);
      } else {
            $children_pids[$i] = $pid;
      }
}

my $stillWaiting;
do {
      $stillWaiting = 0;
      for (my $i = 0; $i < $n; ++$i) {
            if ($children_pids[$i] > 0)
            {
                  if (waitpid($children_pids[$i], WNOHANG) != 0) {
                        # Child is done
                        print "child done\n";
                        $children_pids[$i] = 0;
                  } else {
                        # Still waiting on this child
                        #print "waiting\n";
                        $stillWaiting = 1;
                  }
            }
            #Give up timeslice and prevent hard loop: this may not work on all flavors of Unix
            sleep(0);
      }
} while ($stillWaiting);

print "parent finished\n";
#/usr/bin/perl
严格使用;
使用警告;
使用POSIX“:sys_wait_h”;
子函数
# {{{
{
我的$i=班次;
打印“$i已启动\n”;
$| = 1;
睡眠(10);
打印“$i已完成\n”;
}
# }}}
我的$n=2;
我的孩子们;
对于(我的$i=0;$i<$n;$i++){
如果((my$pid=fork())==0){
func(一美元);
出口(0);
}否则{
$children_pids[$i]=$pid;
}
}
我的美元还在等待;
做{
$stillWaiting=0;
对于(我的$i=0;$i<$n;++$i){
如果($children_pids[$i]>0)
{
if(waitpid($children_pids[$i],WNOHANG)!=0){
#孩子完了
打印“子项完成\n”;
$children_pids[$i]=0;
}否则{
#还在等这个孩子吗
#打印“等待\n”;
$stillWaiting=1;
}
}
#放弃时间片并防止硬循环:这可能不适用于所有类型的Unix
睡眠(0);
}
}在等待中;
打印“父级已完成\n”;
代码基于以下答案:

它工作正常,但父循环占用处理器时间
top
命令给出以下命令:

答案是:

作为额外的奖励,循环将在
waitpid
时阻塞 孩子们正在跑步,所以在等待时不需要忙循环


但对我来说,这并不妨碍。怎么了?

您正在传递
WNOHANG
标志,该标志使呼叫不阻塞。删除此标志,然后
waitpid
将以0%的CPU等待,直到子进程退出

如果采用这种方法,可以简化代码。在子项完成之前,不需要循环,因为阻塞
waitpid
调用将为您完成此操作:

for (my $i = 0; $i < $n; ++$i) {
    if ($children_pids[$i] > 0) {
          waitpid($children_pids[$i], 0);
          print "child done\n";
          $children_pids[$i] = 0;
    }
}
for(我的$i=0;$i<$n;++$i){
如果($children_pids[$i]>0){
waitpid($children_pids[$i],0);
打印“子项完成\n”;
$children_pids[$i]=0;
}
}

或者,将
sleep
调用更改为等待一秒钟。然后,您的程序将每秒检查已完成的子线程,而不会提高CPU使用率。

由于您的父线程在等待其子线程时实际上没有执行任何操作,我将简化为

#!/usr/bin/perl    
use strict;
use warnings;
$| = 1; # autoflush

sub func{
    my($i) = @_;
    print "$i started\n";
    sleep(10);
    print "$i finished\n";
}

my $n = 2;
my @children_pids;

for my $i ( 0..($n-1) ) { # faster, and clearer than the C-style for loop
    my $pid = fork;
    die "Unable to fork" unless defined $pid; # check for errors
    if ( $pid == 0) { # child
        func($i);
        exit(0); # may need to be POSIX::_exit()
    } else { # parent
        push @children_pids, $pid; # don't allow undef or 0 on the list
    }
}

# while( @children_pids ){
#    waitpid shift @children_pids, 0;
# }

waitpid $_, 0 for @children_pids;

print "parent finished\n";

如果您的perl是用IThreads编译的,则可以使用该模块。
(在Windows上进行仿真需要读取)

使用还可以更轻松地执行最初尝试的操作,在线程完成时连接线程

use strict;
use warnings;
use threads (); # not using async
$| = 1; # autoflush

sub func{
    my($i) = @_;
    print "$i started\n";
    sleep(rand(10)); # randomize the order of completion for this example
    print "$i finished\n";
    return $i; # <===
}

my $n = 10;

for my $i ( 0..($n-1) ){
   my $thread = threads->create( \&func, $i ); # ask for scalar value
   die "unable to create thread $i" unless defined $thread;
}

while( threads->list ){
    # join the threads that are done
    for my $thread ( threads->list(threads::joinable) ){
        print 'thread-id: ',  $thread->tid, ' returned: ', $thread->join, "\n";
    }

    # be nice to other threads and processes
    threads->yield;

    # allows the threads to "bunch up" for this example
    # not necessary for real code.
    sleep 2;
}

我想我可以把它写成:
while(@children_-pids){my$pid=shift@children_-pids;next除非$pid;waitpid$pid,0;}
这可以简化为:
while(@children_-pids){waitpid(shift@children_-pids,0)}
如果你永远不允许把0(或
undef
)放在列表上。