2011-06-22 5 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(); 
} 

$ログファイルがあります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では、2つのグローバル変数がインクリメントされていますが、Perlのメインループではまだ0になっています。私はInputEventハンドラからプリント出力を行うことができますが、グローバル変数を変更しないのはなぜですか?

何が問題になりますか?

+0

世界に尋ねるとすぐに、その答えはより明らかになります:おそらくPOEの可変スコープはこれと関係があります:http://stackoverflow.com/questions/1064273/how-does-variable-scoping-ポイセッションでの作業 – 0xDEADBEEF

答えて

5

perlでのスレッド化は、他の言語と同じように動作しません。プログラム空間は共有されません。スレッドの作成では、現在のスレッドは新しいスレッドにコピーされます。新しいスレッドは親スレッドとは別のものです(各スレッドには独自のperl解釈があります)。スレッド間で通信したい場合は、threads :: shared、Thread :: Queue、Thread :: Semaphoreを見てください。ここで上記anydotの提案から、次の

0

は答えます:

は、スレッドを開始する前に、入力されたイベントでは、共有キュー

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";} 
    } 

他の方法もありますが、これは私にとってはうまくいきます。 多くのありがとうございます。

関連する問題