3

UIを作成し、ボタンを押した後に長いプロセスを実行するWindows XP上のActiveStates Active Perlのバージョン5.10ビルド1004でPerlスクリプトを実行しています。このプロセス中に、このスレッドの実行中に何が起こっているかについてのステータスで 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

問題の 1 つは、リストボックス変数をスレッド間で共有する必要があることです。Tk はリストボックス変数を直接共有することに満足していないようなので、2 つのコピーを作成し、共有バージョンを非共有バージョンにコピーする定期的なステータス更新を設定しました。

ただし、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 に答える