【问题标题】:Perl Update UI on Long ThreadPerl 在长线程上更新 UI
【发布时间】:2011-04-25 19:51:35
【问题描述】:

我有一个 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?

谢谢

韦斯利

【问题讨论】:

    标签: multithreading perl user-interface tkx


    【解决方案1】:

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

    但是,在 Tkx 中使用线程可能有点冒险。当我尝试join 线程而不是detach 时,我遇到了段错误,如果我将my $t 移动到startWork() 中,我会收到以下代码的段错误。 This discussion 建议您可能需要在创建任何 Tk 小部件之前启动线程,以使其可靠地工作。

    这是我最终得到的代码:

    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();
    

    【讨论】:

    • 我进行了更改,现在我无法与我的列表框交互,也无法使用其他线程插入该变量的文本进行更新。看起来列表框已经被遗忘了。我的 UI 的其余部分工作正常。
    • @Wesley 我猜-listvariable 不能直接在线程之间共享,我看看能不能重现这个问题。
    • 谢谢,如果有帮助,我可以发布我的所有代码,让您了解我目前必须查看的代码是否可以在您的系统上重复。
    • 完美解决方案。感谢所有帮助。
    【解决方案2】:

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

    $outputText = 'some message';
    Tkx::update('idletasks');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-12
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      • 2015-10-11
      相关资源
      最近更新 更多