2010-08-10 47 views
2

我有以下情形:如何在Perl中處理具有依賴關係的調度線程?

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 

我想每個子要開始儘快運行,比等待他們全部完成。

我真的很感謝你幫助爲這個簡單的場景創建一個乾淨的解決方案 - 我是新的多線程。

我不確定它是否有所作爲,但這些子都是在一個對象中。

+0

您已指定'sub_6'條件兩次,且條件部分重疊 - 是一個錯誤? – pilcrow 2010-08-10 13:59:24

+0

@pilcrow謝謝,我更正了這個 – 2010-08-10 14:04:33

回答

4

我建議一個「老闆/工人」的模式,其中一個線程管理子程序中工作線程,誰又將完成後報告他們的狀態回到老闆被執行。

在這個模型中,老闆是唯一需要知道如何訂購任務的線程。它可能是這個樣子:

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) { 
    ... 
} 
0

叉和創建2個進程:

在過程1:

sub_1; sub_3 

在過程2:

sub_2; wait for sub_1 end; sub_4 
+0

這是什麼'等待sub_1結束'語法? 可以從對象的函數中分叉嗎? 有更復雜的依賴和更多的潛艇同時運行的更通用的解決方案? – 2010-08-10 11:42:44

+0

這只是一個通用解決方案的僞代碼。您只需在Perl – 2010-08-10 11:54:11

+1

中找到合適的語法,請參閱編輯的文章。 – 2010-08-10 12:31:38

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

您正在展示一個多線程新手如何在沒有鎖()的情況下訪問全局狀態,以及如何同步^ Wcoordinate線程活動與輪詢循環?讓我們先讓David B.先學習規則,然後掌握規則,然後打破規則。 – pilcrow 2010-08-10 20:18:16

+0

關於鎖定變量的好處,因爲我忽略了它。我已經將該功能添加到示例中。 – Narthring 2010-08-10 21:12:52

+0

你可以通過'%status'上的'cond_wait()'改變爲'cond_broadcast()'來消除睡眠循環。 – pilcrow 2010-08-11 18:20:55

相關問題