如何在等待先前的线程完成时暂停Thread :: Queue访问?

时间:2014-04-04 16:54:26

标签: multithreading perl queue

所以这就是我现在所拥有的:

for my $action (@actionList){
  $q->enqueue([$_, $action]) for @component_dirs;

  print "\nWaiting for prior actions to finish up...\n";
  until (!defined($q->peek())) {}
}

$q->end();
$_->join() for threads->list();

但这似乎不起作用..是否有更好的方法来强制队列等待先前的$action项目完成再允许再次访问?

编辑:奇怪的是,它神奇地开始工作......也许它一直在努力,我只是没有让输出足够明显。无论哪种方式,我的问题仍然存在 - 有更好的方法吗?

1 个答案:

答案 0 :(得分:4)

您的代码不会等到上一个操作完成,它只会浪费CPU直到另一个线程开始处理上一个作业。

对于像“flags”这样的东西,你通常应该使用信号量。信号量是具有updown方法的线程安全计数器。例如,我们可以传递一个信号量以及从零开始的作业。每个线程在完成作业时递增信号量。我们的主线程尝试通过作业计数来减少信号量,这将阻塞直到所有线程都完成:

my $q = Thread::Queue->new;
my @workers = map { threads->create(\&worker, $q) } 1 .. $NUM_WORKERS;

for my $action (@actionList) {
    my $sem = Thread::Semaphore->new(0);
    $q->enqueue([$_, $action, $sem]) for @component_dirs;
    $sem->down(0+@component_dirs);  # wait for the threads
}

$q->end;
$_->join for @workers;

sub worker {
    my ($q) = @_;
    while (my $job = $q->dequeue) {
        my ($component, $action, $sem) = @$job;
        ...
        $sem->up;
    }
}

实际上,我们可以重复使用信号量。

有关详细信息,请参阅Thread::Semaphore docs

此用法类似于barriers