非常に痛いテーマであるPerl + GUI +スレッドに触れます。
痛い、あなたのアプリケーションをスレッドで動作させる試みが失敗するかもしれないので。 プログラムは「ハング」、「segfolit」します。ドキュメントを見ると、ライブラリがスレッドセーフではないことがわかります。 排水溝に費やした時間はありましたか?
ヒント:MainLoop()はイベントループを開始し、コードの実行をブロックするため、Tkx :: MainLoopを呼び出す前にスレッドを作成します。 それはとても簡単でしょう! この条件でコードを書き直しましたが、まだハングしています...
どうする? 抜け道があります。
Boss / Workersモデルとメッセージキューを使用する必要があります。
目的:GUIを使用してアプリケーションを作成し、マルチスレッドを使用します。
「指で」問題を見てみましょう。すべてを抽象的なモデルの形で提示します。
倉庫があります。 あなたは上司に来ます
-こんにちは、この小さなリストを集めてください...
-さて、ここでタスクを部分的に分散させます。作業者がすべてを行います。
店主は、山からタスクを受け取ります(そして、受け取った順に受け取ります)。
同様のキューは、
Thread::Queue
パッケージによって実装されます。
いくつかの方法を使用します
-エンキュー-タスクを置く
-デキュー、dequeue_nb-タスクを引き受ける
dequeueとdequeue_nbの違いは、後者がノンブロッキングであることです。
言い換えると、デキューを呼び出すとき、タスクが表示されるまで待機し、その後にのみタスクを取得します。 2番目の場合、ジョブがない場合、undefが返されます。
while(defined(my $ item = $ queue-> dequeue())){
#アクションを実行します。
}
店主が必要なすべての商品を収集したので、今度はローダーがそれを拾ってあなたに届けます。
...
それでは、実装(簡略版)に取り掛かりましょう。
タスク-> Tk->ボス->労働者->結果

#!/ usr / bin / perl
厳格な使用;
Tkxを使用します。 #ツールキット
スレッドを使用します。 #スレッドを操作する
スレッドを使用::キュー。 #キューを実装します
#キューを作成
my $ queue_tk = Thread :: Queue-> new(); #Tkからタスクを取得
my $ queue_job = Thread :: Queue-> new(); #従業員に送る
my $ queue_box = Thread :: Queue-> new(); #結果
#上司
sub thread_boss {
私の$ self = threads-> self();
私の$ tid = $ self-> tid();
while(defined(my $ item = $ queue_tk-> dequeue())){
print STDERR "ボス($ tid)はTkからタスクを受け取りました:$ item \ n";
#従業員に仕事を送ります
$ queue_job-> enqueue($ item);
}
$ queue_job-> enqueue(undef);
}
#従業員
sub thread_worker {
私の$ self = threads-> self();
私の$ tid = $ self-> tid();
while(defined(my $ job = $ queue_job-> dequeue())){
print STDERR "労働者($ tid)はボスからタスクを受け取りました:$ job \ n";
#いくつかの作業を行う...
print STDERR "ワーカー($ tid)がタスクを終了しました\ n";
#すべてを1つのボックスに入れます;)
$ queue_box-> enqueue( "processed:$ job");
}
$ queue_box-> enqueue(undef);
}
#スレッドを作成
my $ boss = threads-> new(\&thread_boss);
私の$ worker = threads-> new(\&thread_worker);
#UIを作成する
my $ main_window = Tkx :: widget-> new( '。');
私の$ frame = $ main_window-> new_ttk__frame(-padding => q / 10 10 10 10 /);
$ frame-> g_grid();
my $ label = $ frame-> new_ttk__label(-text => 'waiting');
$ label-> g_grid(-row => 0、-column => 0、-columnspan => 2);
#入力フィールド
my $ entry_data = 'ここにデータを入力してください';
my $ entry = $ frame-> new_ttk__entry(-textvariable => \ $ entry_data);
$ button = $ frame-> new_ttk__button(
-text => 'ボスに送信'、
-command => sub {
$ queue_tk-> enqueue($ entry_data);
}、
);
$ entry-> g_grid(-row => 1、-column => 0);
$ button-> g_grid(-row => 1、-column => 1);
#イベントハンドラーWM_DELETE_WINDOW
sub on_destroy {
my $ mw = shift;
#スレッドを終了するundefキューを送信します
$ queue_tk-> enqueue(undef);
$ queue_box-> enqueue( 'finish');
#破壊する
#またはTkx :: destroy( '。')
$ mw-> g_destroy();
}
$ main_window-> g_wm_protocol( 'WM_DELETE_WINDOW'、[\&on_destroy、$ main_window]);
#結果を処理する
サブモニター{
私の$ status_lbl = shift;
私の$ result = $ queue_box-> dequeue_nb;
if($ result ne 'finish'){
if(定義された$結果){
$ label-> configure(-text => "job completed:" .scalar(localtime));
}
Tkx :: after(1000、[\&monitor、$ label]);
}
}
#監視を開始
Tkx :: after(100、[\&monitor、$ label]);
#スレッドを解除する
#それ以外の場合、プログラムの最後に警告が表示されます
#Perlはアクティブなスレッドで終了しました:
#2実行中および未参加
#0終了し、参加していません
#0実行中および切り離し
$ boss-> detach();
$ worker-> detach();
Tkx :: MainLoop();
ネットワーク、データベースを操作するためのマルチスレッドプログラムを作成する場合は、標準ストリームの代わりに、
POE (イベントマシン、非ブロッキングソケット)を使用する方がはるかに適切だと思います。
これはドラフトですが、補足されます。