我有以下情况:
sub_1 can run immediately
sub_2 can run immediately
sub_3 can run only after sub_1 finishes
sub_4 can run only after sub_1 finishes
sub_5 can run only after sub_2 finishes
sub_6 can run only after sub_2 finishes
sub_7 can run only after both sub_1 and sub_2 finish
sub_8 can run only after both sub_1 and sub_2 finish
我希望每个sub尽快开始运行,而不是等待所有sub完成。
我非常感谢您帮助为这个简单的场景创建一个干净的解决方案 - 我是多线程的新手。
我不确定它是否有所作为,但这些潜艇都在一个物体中。
答案 0 :(得分:4)
我建议使用“Boss / Worker”模型,其中一个线程管理要在工作线程中执行的子程序,工作线程又在完成时将其状态报告给老板。
在这个模型中,boss是唯一需要知道如何排序任务的线程。它可能看起来像这样:
use threads;
use Thread::Queue;
use Thread::Pool;
our $done_queue = Thread::Queue->new;
our $work_pool = Thread::Pool->new;
sub sub_1 {
... do the work ...
$done_queue->enqueue('sub_1'); # tell the boss we're all done
}
sub sub_2 {
... do the work ...
$done_queue->enqueue('sub_2'); # tell boss we're done
}
...
# Main loop (boss thread)
$work_pool->enqueue(\&sub_1);
$work_pool->enqueue(\&sub_2);
while (my $sub_name = $done_queue->dequeue) {
# You, the boss thread, keep track of state and
# transitions however you like. You know what's
# just finished and what's finished in the past
...
}
当然,抽象可以使整洁 - 你可以隐藏单个对象后面的池和队列,一个不需要sub_1()
来了解状态队列的对象:
$boss->enqueue( 'sub_1' => \&sub_1 ); # Will return 'sub_1' via await_completed()
$boss->enqueue( 'sub_2' => \&sub_2 ); # Will return 'sub_1'
while (my $sub_name = $boss->await_completed) {
...
}
答案 1 :(得分:1)
这是使用线程和线程共享的可能解决方案。大多数代码只是模拟测试并模拟在完成之前必须“工作”的线程。在该示例中,主线程产生七个线程,每个线程具有他们必须“工作”的随机时间量。线程无法开始工作,直到它们依赖的其他线程(在依赖项数组中设置)完成。您可以更改线程依赖关系并运行几次示例以说明它可以正常工作。
此外,您可以让每个线程在运行后终止,并在所有子线程完成后通过检查状态哈希使主线程终止。
use strict;
use warnings;
use threads;
use threads::shared;
my %status : shared;
my $dependencies = [
{3 => 1}, #three can only run after one has finished...
{4 => 1}, #four can only run after one has finished...
{5 => 2}, #five can only run after two has finished...
{6 => 1}, #etc...
{6 => 2},
{7 => 1},
{7 => 2}
];
main();
sub main{
foreach my $thread_number (1..7){
spawn_thread($thread_number);
}
while(1){
print "I am the main thread\n";
sleep(1);
}
}
sub spawn_thread{
my $thread_number = shift;
$status{$thread_number} = 'wait';
my $thr = threads->new(\&thread_routine, $thread_number);
}
sub thread_routine{
my $thread_number = shift;
my $working_time_left = int(rand(5)) + 1; #make a random time that this thread needs to "work"
while(1){
print "I am thread number $thread_number with status $status{$thread_number}\n";
{
lock(%status);
#see if this thread is active; if so, see if it finished running running
if ($status{$thread_number} eq 'active'){
if ($working_time_left <= 0){
$status{$thread_number} = 'ran';
}
}
else{
#see if we can activate
if ($status{$thread_number} eq 'wait'){
my $can_activate = 1;
foreach my $index (0..$#$dependencies){
if (exists $dependencies->[$index]->{$thread_number}){
if ($status{$dependencies->[$index]->{$thread_number}} ne 'ran'){
$can_activate = 0;
last;
}
}
}
if ($can_activate){
$status{$thread_number} = "active";
}
}
}
}
sleep(1);
if ($status{$thread_number} eq 'active'){ #do "work"
$working_time_left--;
}
}
}
答案 2 :(得分:0)
分叉并创建2个进程:
在流程1中:
sub_1; sub_3
在过程2中:
sub_2; wait for sub_1 end; sub_4