所以这就是我现在所拥有的:
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
项目完成再允许再次访问?
编辑:奇怪的是,它神奇地开始工作......也许它一直在努力,我只是没有让输出足够明显。无论哪种方式,我的问题仍然存在 - 有更好的方法吗?
答案 0 :(得分:4)
您的代码不会等到上一个操作完成,它只会浪费CPU直到另一个线程开始处理上一个作业。
对于像“flags”这样的东西,你通常应该使用信号量。信号量是具有up
和down
方法的线程安全计数器。例如,我们可以传递一个信号量以及从零开始的作业。每个线程在完成作业时递增信号量。我们的主线程尝试通过作业计数来减少信号量,这将阻塞直到所有线程都完成:
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。