5

再構築する必要のあるC++/MFCアプリケーションがあります。このアプリはメインスレッドでほとんどのデータを処理していたため、入力をブロックしていました。今度は、すべてのGUI更新がPostMessageを介して行われるように変更したいと思います。

残念ながら、私はこの目標を達成する方法についての良い情報源を見つけることができないようです。

今、私は、クリティカルセクションで保護された優先キュー、このキューを処理するワーカースレッド(while(true))、およびデータへのポインターをメインスレッドに送信するPostMessageメカニズムを作成することを考えています。

このアプローチで私を怖がらせるのは、PostMessageがメインスレッドに到達することがまったく保証されていないことです。したがって、正しく理解していれば、メモリリークが発生する可能性があります。

2番目の問題は、別のアプリがカスタムメッセージをアプリケーションに送信でき、アプリケーションがWPARAMまたはLPARAMをポインターとして逆参照しようとし、それによってAVが発生する可能性があることです。

そのようなタスクのベストプラクティスを知っている人はいますか?

データは、Webコントロール用のHTMLコンテンツ、またはリストボックスやドロップダウンなどの他のコンテンツにすることができます。

4

3 に答える 3

11

あなたのメッセージはそこに届きます。PostMessageが機能することが保証されていない理由はわかりませんが、機能します。(編集:PostMessage()がTRUEを返すと仮定します!戻りコードを確認してください!)

スレッド間でデータを通信するためにキューを使用することは避けたいと考えています。両方のスレッドがアクセスするキューはすべて保護する必要があります。両側にハードロックを追加すると、アプリケーションがシリアル化されます。

代わりに、を使用してヒープ上にデータnewを含むデータ構造を作成し、他のスレッドに「データがあります。これがあります」と伝えます。次に、受信スレッドはそのデータポインターの所有権を取得し、それを実行deleteする責任があります。このようにすると、ハードロックは発生しません。

今、唯一のトリックは「他のスレッドに教える」部分を理解することですが、それも簡単です。

ワーカースレッドからメインスレッドにデータを送信する場合は、次を使用しますPostMessage()

worker_thread_proc()
{
// ..

  // Create the data object you're going to pass to the MT
  MyData* data = new MyData;
  data->some_value_ = "foo";

  // Pass it:
  PostMessage(main_wnd, WM_YOU_HAVE_DATA, reinterpret_cast<WPARAM>(data), 0);
}

...メインスレッドはこれを処理してから、データを削除します。

MainWnd::OnYouHaveData(WPARAM wp, LPARAM)
{
  std::auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
  my_widget->set_text(data->some_value_); // you get the idea
}

外部アプリのカスタムメッセージが自分のものにぶつかるのが心配な場合は、RegisterWindowsMessage()を使用してWindowsに一意のメッセージIDを与えることができます。ここでの唯一の課題は、メッセージの正しい名前を選択することです。

メインスレッドからワーカースレッドにデータを送信する場合は、上記と同じようにPostMessage()実行できますが、壁を越えてデータを送信する代わりに、 QueueUserAPC()を使用できます(ワーカーの広告がアラート可能であることを確認してください)待機状態-リンクされたドキュメントの注釈を読んでください)またはPostThreadMessage()

編集:

OPでのコメントによると、PostMessage()が機能しないことを心配している理由がわかりました。

はい、Windowsメッセージキューのサイズには厳しい制限があります。デフォルトでは、キューに含めることができるメッセージは4,000件のみです。(レジストリ設定では、これを最大10,000まで調整できます)。

キューがいっぱいにPostMessage()なると、への呼び出しはすべてエラーコードで失敗します。GetLastError()をチェックすると(現在どのエラーコードが返されるかは覚えていません)、メッセージキューがいっぱいであることが明らかになります。

母鶏のように聞こえるわけではありませんが、API呼び出しからの戻り値を実際に確認する必要があります。しかし、それを超えて、メッセージキューの上限で実行している場合は、とにかくアプリケーションが壊れていると思います。キューがいっぱいになると、アプリケーションは呼吸できなくなります。画面がペイントされず、実行する処理が古くなり、あらゆる種類の悪いことが起こります。これが現在の状況である場合は、その理由を調べる必要があるかもしれません。

于 2010-09-27T21:50:40.300 に答える
2

2つのキューを使用します。1つはワーカースレッドに送信される作業要求用で、もう1つはメインスレッドに戻る結果用です。PostMessageを使用してメインスレッドをウェイクアップし、キューをチェックするように指示できますが、メッセージにパラメータは必要ありません。

于 2010-09-27T21:22:55.533 に答える
1

私は少し前に同様の問題を解決しました。バックグラウンドスレッドからUI(メイン)スレッドに流れる必要のあるデータ(またはアクション)を保持するために、シングルトンキューを作成しました。キューはクリティカルセクションによって保護されています。バックグラウンドスレッドはそのデータをキューに入れ、メッセージを投稿します。メッセージにはデータが含まれていません。「ねえ、メインスレッド、キューを見てください。あなたのために仕事があります」という単純なウェイクアップ呼び出しとして機能します。

これにより、メモリやその他のリソースがリークするリスクがなくなります。キューには、含まれているすべてのデータを使用して安全に破棄できます。

于 2010-09-27T21:30:18.947 に答える