3

我有一个 Perl 脚本在 Windows xp 上的 ActiveStates Active Perl 版本 5.10 build 1004 上运行,它创建一个 UI,然后在按下按钮后运行一个很长的过程。在这个过程中,我想用这个线程执行期间发生的事情的状态来更新 UI(一个列表框)。这是代码的精简版本。

#!/usr/local/bin/perl

use warnings;
use strict;
use Tkx;
use threads;
use threads::shared;

my $outputText = " {a} {b}";

my $mw = Tkx::widget->new(".");
$mw->g_wm_title("MD5 Checker");
$mw->g_wm_minsize(300,200);
my $content = $mw->new_ttk__frame(-padding => "12 12 12 12");
my $btnCompare = $content->new_ttk__button(-text => "Compare", -command => sub{startWork()});
my $lstbxOutput = $content->new_tk__listbox(-listvariable => \$outputText, -height => 5);
my $scollListBox = $content->new_ttk__scrollbar(-orient => 'vertical', -command => [$lstbxOutput, 'yview']);
$lstbxOutput->configure(-yscrollcommand => [$scollListBox, 'set']);

sub startWork()
{
    print "Starting thread \n";
    my $t = threads->create(\&doWork, 1);
    sleep (5);
    print $outputText . "\n";
}

sub doWork()
{
    for (my $a = 0; $a<10; $a++)
    {
        $outputText .= " {$a}";
        print "Counting $a\n";
        sleep(2);
    }
    print "End thread\n";
}

目前打印命令用于我的调试,所以我知道主线程和子线程在做什么。从我所读到的关于线程的内容中,我需要use threads::shared;允许线程共享变量。目前,我的列表框在子线程执行期间或线程结束时根本没有更新。如果没有线程,列表框将在主线程完成循环后更新。在线程执行期间让 UI 更新我缺少什么?

谢谢

卫斯理

4

2 回答 2

2

一个问题是列表框变量需要在线程之间共享。tk似乎对listbox变量直接共享不满意,所以我做了两份,并设置了定期状态更新,将共享版本复制到非共享版本。

但是,在 Tkx 中使用线程可能是有风险的。当我尝试join使用线程而不是线程时,我遇到了段错误,如果我移动到里面detach,我会收到下面代码的段错误。这个讨论表明您可能需要在创建任何 Tk 小部件之前启动线程以使其可靠地工作。my $tstartWork()

这是我最终得到的代码:

my $outputTextShared :shared = " {a} {b}";
my $outputText = " {a} {b}";

my $t;
sub startWork()
{
    print "Starting thread \n";
    $t = threads->create(\&doWork, 1);
}

sub updateStatus()
{
    $outputText = $outputTextShared;
}

sub doWork()
{
    threads->detach();
    for (my $a = 0; $a<10; $a++)
    {
        $outputTextShared .= " {$a}";
        print "Counting $a\n";
        sleep(1);
    }
    print "End thread\n";
}

my $update;
$update = sub {
    Tkx::after (1000, $update);
    updateStatus();
};
Tkx::after (1000, $update);

Tkx::MainLoop();
于 2011-04-25T20:23:47.623 回答
1

线程很好,因为 UI 不会阻塞,如果花费太长时间,您可以执行诸如终止子进程之类的操作。然而,这种力量伴随着复杂性。如果您只关心更新 UI 中的任务状态,您可以不使用线程来完成;你只需要手动完成。

$outputText = 'some message';
Tkx::update('idletasks');
于 2011-05-16T19:52:20.723 回答