2011-06-22 46 views
1

在此程序中POE :: Wheel :: FollowTail適用於跟蹤文件的尾部,它也在單獨的線程中運行以簡單地監視編譯作業的進度。
在InputEvent處理程序中有一個粗略的正則表達式來提取編譯結果,並且在那裏一切工作正常,但我無法獲得任何結果值可以在此子外部訪問。即使我將結果變量放在全局範圍內,它們也不會被修改。Perl POE :: Wheel :: FollowTail在不修改全局變量的線程中運行

該程序由一個進程運行編譯作業,另一個正在看日誌和主循環等待。

全球範圍:

my $Pass = 0; 
my $Done = 0; 

然後揭開序幕監測:

threads->create(\&StartWatcher); 

凡手錶日誌文件子是這樣的:

sub StartWatcher 
{ 
my $logfile = "filename.log"; 

# Create the logfile watcher 
POE::Session->create 
    (
    inline_states => 
     { 
     _start => sub 
      { 
      $_[HEAP]{tailor} = POE::Wheel::FollowTail->new(Filename => $logfile, InputEvent => "got_log_line",); 
      }, 
     got_log_line => sub 
      { 
      $Pass +=() = $_[ARG0] =~ /^\d+.*vcproj \- 0 error\(s\), \d+ warning\(s\)/g; 
      $Done +=() = $_[ARG0] =~ /^\d+.*vcproj \- \d+ error\(s\), \d+ warning\(s\)/g; 
      print "POE InputEvent Pass: $Pass, Done: $Done\n"; # Debug output 
      }, 
     } 
    ); 

POE::Kernel->run(); 
} 

的$ logfile是由使用Win32 :: Process :: Create開始的Visual Studio編譯作業編寫,主要的Perl執行就在此處循環等待編譯器終止,並且每秒產生一個狀態輸出。

while('true') 
    { 
    $ProcessObj->Wait(100); # milliseconds wait 
    $ProcessObj->GetExitCode($exitcode); 
    if ($exitcode == STILL_ACTIVE) 
     { 
     "Compiling... [$Done/$Count] Pass: $Pass Failed: $failed" 
      if($RunCounter++ % 10 == 0); 
     next; 
     } 
    last; 
    } 

產生的輸出是與此類似:

POE InputEvent Pass: 1, Done: 1 
Compiling... [0/91] Pass: 0 Failed: 0       

即在InputEvent處理函數got_log_line中,兩個全局變量已經遞增,但在Perl主循環中它們仍然爲零。我意識到我可以從InputEvent處理程序執行打印輸出,但爲什麼它不修改全局變量?

什麼問題?

+0

當然,只要你問世界的答案就會變得更加明顯:POE中的變量範圍可能與此有關:http://stackoverflow.com/questions/1064273/how-does-variable-scoping-工作在一個-POE-會議 – 0xDEADBEEF

回答

5

在perl中的線程工作方式與在其他語言中的工作方式不同,程序空間不共享。在線程創建中,當前線程被複制到一個新線程中,該線程與父線程分離(每個線程都有自己的perl解釋)。如果你想在線程之間進行通信,請查看threads :: shared,Thread :: Queue和Thread :: Semaphore。

0

從上面這裏anydot的建議以下就是答案:

啓動線程之前,創建一個共享隊列

use threads; 
use Thread::Queue; 
use threads::shared; 
my $queue:shared = Thread::Queue->new(); 

在輸入事件,創建一些共享的數據入隊

 my %data:shared =(); 

     $data{PASS_VCPRJ_COUNT} =() = $_[ARG0] =~ /^\d+.*vcproj.*0 error.*\d+ warning/g; 
     $data{DONE_VCPRJ_COUNT} =() = $_[ARG0] =~ /^\d+.*vcproj.*d+ error.*\d+ warning/g; 
     $queue->enqueue(\%data) if($data{DONE_VCPRJ_COUNT} ne 0 || $data{PASS_VCPRJ_COUNT} ne 0); 

然後在屏幕更新代碼中,將它出列,這裏是非阻塞的

if (defined(my $item = $queue->dequeue_nb())) 
    { 
    foreach my $key(%$item) 
    {print "$key  $item->{$key}\n";} 
    } 

還有其他的方法,我敢肯定,但這對我很有用。 非常感謝。