- 論壇徽章:
- 12
|
本帖最后由 523066680 于 2023-04-22 13:24 編輯
環境:Win10, Strawberry Perl
經常遇到需要多線程處理的需求,但是在終端混合輸出的結果非;靵y,即使每條信息加上線程ID,又或是使用不同的縮進。
最初考慮在線程間共享GUI句柄,結果發現僅有的幾個GUI框架并不支持線程共享。
于是改了方案,單獨開一個線程跑GUI,創建一個線程共享的字符串數組,存儲日志。
通過 open $H, ">", \$str 的方式為字符串變量創建輸出流句柄,然后 select $H 取代STDOUT輸出。
在GUI的文本顯示模塊中動態更新字符串內容,目的達成。
- # Code By 523066680
- use utf8;
- use Modern::Perl;
- use Encode;
- use threads;
- use threads::shared;
- use Time::HiRes qw/sleep time/;
- use IUP ':all';
- STDOUT->autoflush(1);
- my $th_count = 8;
- # 不同線程的日志緩存
- my @log :shared;
- @log = map { utf8("線程 $_ \n") } ( 0 .. $th_count ); # 0 占位
- my @ths;
- # 創建線程
- grep { push @ths, threads->create( \&th_func, $_ ) } ( 1 .. $th_count );
- push @ths, threads->create( \&GUI, 4 );
- # 等待運行結束
- while ( threads->list(threads::running) ) { sleep 0.2 };
- # 線程分離/結束
- grep { $_->detach() } threads->list(threads::all);
- sub th_func
- {
- my ( $id ) = @_;
- $SIG{'KILL'} = sub { threads->exit(); };
- # printf "%d %s\n", $id, $log[$id];
- open my $FH, ">>:utf8", \$log[$id];
- select $FH;
- my $n = 1;
- while ( 1 )
- {
- printf "線程 %d -> %03d\n", $id, $n++;
- sleep 0.2;
- }
- }
- sub GUI
- {
- our @edit;
- for my $n ( 1 .. $th_count )
- {
- push @edit, IUP::Text->new(
- FONT => "Simsun, 10",
- MULTILINE => "YES",
- BORDER => "YES",
- SCROLLBAR => "VERTICAL",
- EXPAND=>"YES",
- BGCOLOR => "#000000",
- FGCOLOR => "#FFFFFF",
- VALUE => "",
- );
- }
- my $box1 = IUP::Vbox->new(
- TABTITLE => "1~4",
- child => [
- IUP::Hbox->new(
- child => [ $edit[0], $edit[1] ],
- GAP => 5,
- MARGIN => "5x5"
- ),
- IUP::Hbox->new(
- child => [ $edit[2], $edit[3] ],
- GAP => 5,
- MARGIN => "5x5"
- ),
- ],
- EXPAND => 1,
- GAP => 5,
- MARGIN => "5x5"
- );
- my $box2 = IUP::Vbox->new(
- TABTITLE => "5~8",
- child => [
- IUP::Hbox->new(
- child => [ $edit[4], $edit[5] ],
- GAP => 5,
- MARGIN => "5x5"
- ),
- IUP::Hbox->new(
- child => [ $edit[6], $edit[7] ],
- GAP => 5,
- MARGIN => "5x5"
- ),
- ],
- EXPAND => 1,
- GAP => 5,
- MARGIN => "5x5"
- );
- my $tabs = IUP::Tabs->new( child => [$box1, $box2 ], TABTYPE=>"TOP",
- PADDING => "10x10",
- FONTSIZE => "12",
- T**RIENTATION => "HORIZONTAL",
- );
- my $dlg = IUP::Dialog->new(
- child => $tabs,
- TITLE => "Console",
- SIZE => "450x250",
- );
- IUP::Timer->new(ACTION_CB => msg_update->( \[url=home.php?mod=space&uid=31104]@edit[/url] ), TIME => 200, RUN=>'YES');
- $dlg->ShowXY( IUP_CENTER, IUP_CENTER );
- IUP->MainLoop;
- # 如果GUI線程結束
- for ( threads->list(threads::all) )
- {
- if ( $_->tid() != threads->tid() )
- {
- $_->kill("KILL")->detach();
- printf "detach %d\n", $_->tid();
- }
- }
- }
- # 日志更新顯示
- sub msg_update
- {
- my ( $edit ) = @_;
- # 記錄每個ID日志的offset,只打印增量的部分
- # 解決滾動條反彈到頂部的問題 - 如果每次都使用 $obj->VALUE 打印整個日志的話
- my @offset = map {0} ( 0 .. $th_count );
- return sub
- {
- for my $id ( 1 .. $th_count )
- {
- my $len = length( $log[$id] );
- if ( $offset[$id] == 0 )
- {
- $log[$id] =~ s/\n$//;
- $edit->[$id-1]->APPEND( $log[$id], 0 );
- $offset[$id] = $len - 1; # 去掉一個換行符
- }
- elsif ( $len > $offset[$id] )
- {
- my $str = substr( $log[$id], $offset[$id] );
- $str=~s/\n$//;
- $edit->[$id-1]->APPEND( $str );
- $offset[$id] = $len;
- }
- #$edit->[$id-1]->VALUE( $log[$id] );
- }
- return IUP_DEFAULT;
- };
- }
- sub gbk { encode('gbk', $_[0]) }
- sub utf8 { encode('utf8', $_[0]) }
- sub u2gbk { encode('gbk', decode('utf8', $_[0])) }
- sub uni { decode('utf8', $_[0]) }
復制代碼
|
|