非同期イベントがない別のワーカー スレッドに関数を移動します。
メイン スレッドの非同期イベントは何らかのメッセージを何らかのキューにポストする必要があるため、ワーカー スレッドの実行が完了すると、メイン スレッドは新しいパラメーターでもう一度開始します。
いくつかの詳細情報を含む更新がありました。関数が RS232 を介して受信したデータを介して動作するか、または何も動作しないと仮定すると (推測)、GUI 更新のようなことを行うと、次のアプローチをスケッチします。
- フォームの Windows メッセージング キューをアラートに使用します。
- データの受け渡しには、インターロックされたキュー オブジェクトを使用します。(はい、Windows メッセージにポインターを入れることができることは知っていますが、もう少しタイプ セーフが必要です)
- 長い処理には外部作業スレッドを使用します。
詳細:
- WM_USER の VCL ソースを grep し、パターンを確認します。Work_Complete、Work_Request、Work_EmptyQueue の 3 つのメッセージ ID 定数を宣言します。そして、対応するメッセージメソッドが形になっています。
- OmniThreadLibrary からのスレッドセーフなキューを使用します。ただし、System.Contnrs.TQueue または System.Generics.Collections.TQueue をサブクラス化して、それらのすべてのデータ受け渡しメソッドをクリティカル セクションにラップすることができます。全体として、OmniThreadLibrary パイプラインが適している場合は、それを参照することをお勧めします
- これは、ハードウェア データ作業アプリの標準的な方法です。それはMS-DOSデバイスドライバーです。またはいくつかの組み込みデバイス。高速で無駄のないデータ保存を長時間の作業から分離する必要があります。
したがって、RS232 イベント ハンドラは COM からデータを読み取り、それを TBytes に入れ、そのパケットを入力 TQueue に追加します。もう少し複雑なアプローチは、Queue に COM からのデータが既に含まれているかどうかを確認し、新しいパケットを個別にパットするのではなく、新しいパケットを古いものと集約することです。それにはより慎重なロックが必要になるため、ここに集約することはおそらくろうそくの価値がありません
タイマーは、空のパケット (長さゼロのバイト配列) を作成し、同様にキューに入れます。そのタイマーにも渡すデータがある場合、それはバリアントレコードまたは個別の入力キューなどである必要があります。しかし、情報がなければ、タイマーは情報を送信しないようですが、アラート自体を送信します
あなたの言葉によると、Timer イベントと RS232 イベントは別々のスレッドで動作します。私はそれについて疑問を持っていますが、私はあなたを信頼しなければなりません。
ワークロードをエンキューした後 (入力キューの通知イベントなど)、win32 PostMessage(MainForm.Handle, work_request) を実行します。結局、スレッド制御を 1 か所に集中させたいと考えています。スレッドを分離した状態に保つには、メッセージを投稿する必要があります。
フォームの work_request ハンドラのメイン スレッドで、入力キューがまだ空でないかどうかを調べます。そうでない場合は、ワーカー スレッドの状態を確認します。中断された場合は、再開します。
ワーカー スレッドは、入力キューに何かがあるように見えます。
- パケットをキューからローカル変数に抽出します
- 潜在的に長い処理を行う
- 「作業結果」パケットを出力します。これは、キーと値のペアのコレクション、または入力されたデータ フィールドと無視されるデータ フィールドのセットを含むデータ フィールドのレコードである可能性がある GUI 更新であると仮定します。
- そのパケットを出力キューにエンキューします (キューに入れ、Work_Complete メッセージをメイン フォームにポストします)。
- 1 にループします。
入力キューが空の場合、関数は終了し、スレッドは PostMessage Work_EmptyQueue を実行し、後でより多くの作業を行うか解放するために目覚めるまで自身を一時停止します。
MainForm (再びメイン スレッド) が Work_Complete を受け取ると、
- 出力キューからすべてのパケットをローカル変数に抽出します
- それらをマージします。(p1=(label1='aaaa', label2='bbbb') と p2=(label3='cccc', label1='dddd') がある場合、累積タスクは (label1='dddd', label2 ='bbbb', label3='cccc');
- それらを適用します(実際にはGUIを更新します)
出力キューが空の場合、手順 2 と 3 は省略されます (前の手順でマージが発生した場合は省略されます)。でも4位ではない。ステップ 1 と 2 は別です。キュー操作はスレッド連動であるため、ステップ 1 の目標はデータをできるだけ速く抽出することです。マージンは現地で行う必要があります。
MainForm が Work_EmptyQueue を受け取ると、入力キューが空でないかどうかを確認し、ワーカー スレッドを再開する可能性があります。オプションで、ステータスの GUI 更新などを行うこともできます。
それがラフスケッチです。それはあなたに特定の引用をよりよく刻むことができます。