8

ほとんどのアクションに時間がかかるアプリケーションがあり、GUIの応答性を常に維持したいと考えています。ユーザーによってトリガーされるアクションの基本的なパターンは次のとおりです。

  1. アクションを準備します(メインスレッドで)
  2. アクションを実行します(GUIの応答性を維持しながらバックグラウンドスレッドで)
  3. 結果を(メインスレッドで)表示します

私はこれを達成するためにいくつかのことを試みましたが、それらすべてが長期的に問題を引き起こしています(特定の状況ではランダムアクセス違反のようです)。

  1. アクションを準備してから、バックグラウンドスレッドを呼び出し、バックグラウンドスレッドの最後で、を使用してメインスレッドでイベントSynchronizeを呼び出します。OnFinish
  2. アクションを準備してから、バックグラウンドスレッドを呼び出し、バックグラウンドスレッドの最後で、を使用PostMessageして結果の準備ができたことをGUIスレッドに通知します。
  3. アクションを準備してから、バックグラウンドスレッドを呼び出し、バックApplication.ProcessMessagesグラウンドスレッドが終了するまでビジーウェイト(呼び出し中)してから、結果の表示に進みます。

私は別の選択肢を思い付くことができず、これのどれも私にとって完璧に機能しませんでした。これを行うための好ましい方法は何ですか?

4

3 に答える 3

5

ここでOTL作成者によって示されているように、OTLを使用して質問されたパターンを実装できます。

于 2012-09-14T13:32:13.063 に答える
5

1)「オリジナルのDelphi」の方法であり、同期されたメソッドが実行されるまでバックグラウンドスレッドを強制的に待機させ、システムを私が満足しているよりも多くのデッドロックの可能性にさらします。TThread.Synchronizeは少なくとも2回書き直されました。D3で一度使用しましたが、問題がありました。私はそれがどのように機能するかを見ました。二度と使用しませんでした。

2)私が最もよく使うデザインです。私はapp-lifetimeスレッド(またはスレッドプール)を使用し、スレッド間通信オブジェクトを作成し、TObjectQueueの子孫に基づく生産者/消費者キューを使用してそれらをバックグラウンドスレッドにキューイングします。バックグラウンドスレッドはオブジェクトのデータ/メソッドを操作し、結果をオブジェクトに格納し、完了すると、オブジェクトをPostMessage()(lParamにキャスト)してメインスレッドに戻し、結果をメッセージでGUI表示します-ハンドラー(lParamを再度キャストします)。メインGUIスレッドのバックグラウンドスレッドは、同じオブジェクトを操作する必要はなく、相互のフィールドに直接アクセスする必要もありません。

私は、GUIスレッド(RegisterWindowClassとCreateWindowで作成)の非表示ウィンドウを、PostMessageのバックグラウンドスレッド、LParamのcommsオブジェクト、およびWParamとしての「ターゲット」TwinControl(通常はTFormクラス)に使用します。非表示ウィンドウの簡単なwndprocは、TwinControl.Perform()を使用して、LParamをフォームのメッセージハンドラーに渡します。これは、オブジェクトをTForm.handleに直接PostMessagingするよりも安全です。残念ながら、ウィンドウが再作成されると、ハンドルが変更される可能性があります。非表示のウィンドウがRecreateWindow()を呼び出すことはないため、そのハンドルは変更されません。

生産者/消費者キュー'GUIから'、スレッド間通信クラス/オブジェクトおよびPostMessage()'GUIへ'はうまく機能します-私は何十年もそれをやっています。

commsオブジェクトの再利用もかなり簡単です-起動時にループでロードを作成し(できれば、commsオブジェクトがすべてのフォームよりも長持ちするように初期化セクションで)、それらをPCキューにプッシュします-それがプールです。commsクラスにプールインスタンスのプライベートフィールドがある場合は簡単です。'releaseBackToPool'メソッドはパラメーターを必要とせず、複数のプールがある場合は、オブジェクトが常に独自のプールに解放されるようにします。

3)DavidHeffermanのコメントを実際に改善することはできません。ただそれをしないでください。

于 2012-09-14T13:48:05.553 に答える
1

スレッド間でデータをメッセージとして通信できます。

スレッド1:

  1. データ構造にメモリを割り当てる
  2. 記入してください
  3. この構造体へのポインターを使用してThread2にメッセージを送信します(Windowsメッセージを使用するか、キューを実装して、enqueメソッドとdequeueメソッドに競合状態がないことを確認します)
  4. Thread2から応答メッセージを受信する可能性があります。

スレッド2:

  1. Thread1からデータ構造へのポインタを含むメッセージを受信します
  2. データを消費する
  3. データ構造のメモリの割り当てを解除します
  4. 同様の方法でThread1にメッセージを送り返す可能性があります(おそらくデータ構造を再利用しますが、割り当てを解除しません)

GUIをライブにするだけでなく、処理に時間がかかる入力の処理中に何らかの入力に応答する必要がある場合は、GUI以外のスレッドが複数になる可能性があります。

于 2012-09-14T13:10:01.880 に答える