痛い、あなたのアプリケーションをスレッドで動作させる試みが失敗するかもしれないので。 プログラムは「ハング」、「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 (イベントマシン、非ブロッキングソケット)を使用する方がはるかに適切だと思います。
これはドラフトですが、補足されます。