Multithreading Perl POE::Wheel::FollowTail在不修改全局变量的线程中运行

Multithreading Perl POE::Wheel::FollowTail在不修改全局变量的线程中运行,multithreading,perl,poe,Multithreading,Perl,Poe,在这个程序中,POE::Wheel::FollowTail可以很好地跟踪文件的尾部,它还可以在单独的线程中运行,以简单地监视编译作业的进度。 在InputEvent处理程序中,有一个用于提取编译结果的粗糙正则表达式,并且一切正常,但我无法在该子类之外获得任何可访问的结果值。即使我将结果变量放入全局范围,它们也不会被修改 该程序由一个运行编译作业的进程、另一个监视日志的进程和等待的主循环组成 全球范围: my $Pass = 0; my $Done = 0; 然后启动监控: threads-&g

在这个程序中,POE::Wheel::FollowTail可以很好地跟踪文件的尾部,它还可以在单独的线程中运行,以简单地监视编译作业的进度。 在InputEvent处理程序中,有一个用于提取编译结果的粗糙正则表达式,并且一切正常,但我无法在该子类之外获得任何可访问的结果值。即使我将结果变量放入全局范围,它们也不会被修改

该程序由一个运行编译作业的进程、另一个监视日志的进程和等待的主循环组成

全球范围:

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处理程序get_log_行中,两个全局变量已递增,但在Perl主循环中,它们仍然为零。我意识到我可以从InputEvent处理程序进行打印输出,但为什么它不修改全局变量呢


出什么问题了?

perl中的线程与其他语言中的线程工作方式不同,程序空间不共享。在创建线程时,将当前线程复制到新线程中,新线程与父线程分开,每个线程都有自己的perl解释指令。如果要在线程之间通信,请查看threads::shared、Thread::Queue和Thread::Semaphore。

perl中的线程与其他语言中的线程工作方式不同,程序空间不共享。在创建线程时,将当前线程复制到新线程中,新线程与父线程分开,每个线程都有自己的perl解释指令。如果您想在线程之间进行通信,请查看threads::shared、Thread::Queue和Thread::Semaphore。

根据上面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";}
    }
我相信还有其他方法,但这对我来说很有效。
非常感谢。

根据以上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";}
    }
我相信还有其他方法,但这对我来说很有效。
非常感谢。

当然,只要你问世界,答案就会变得更加明显:也许POE中的变量范围与此有关:当然,只要你问世界,答案就会变得更加明显:也许POE中的变量范围与此有关: