1

私の Delphi アプリケーションには、メッセージ待機ループを持つスレッドがあります。メッセージを受信するたびに、何らかの作業を開始します。そのスレッドの実行手順は次のとおりです。

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

アプリケーションを使用していくつかのテストを行ったところ、GetMessage 関数がメイン スレッドに依存していることがわかりました。これは、メイン スレッドが何らかの作業を行っている間、メッセージが受信されるのを待っているにもかかわらず、スレッドの GetMessage 関数が返されないことを意味します (メッセージは、PostThreadMessage 関数を使用してさらに別のスレッドによって送信されます: PostMessage( MyThreadId、WM_MyMessage、0、0))。

メイン スレッドが作業を終了するか、Application.ProcessMessages メソッドが呼び出されたときにのみ、GetMessage が返され、スレッドが作業を開始します。この種のスレッド間通信を実装することで、スレッドが独立して動作することは確実であり、スレッドに直接送信されたメッセージの受信がメイン スレッドに依存するとはまったく予想していませんでした。

テストを実行するために、メイン スレッドで WaitForSingleObject 関数を使用し、イベントを数秒間待機しました。これは、別のスレッドからメッセージが送信されたにもかかわらず、自分のスレッドが何も機能していないことに気付いたときです。WaitForSingleObject 関数が最終的に待機を終了し、メイン スレッドがアイドル状態になると、スレッドの GetMessage 関数が返されました。

誰かがなぜこのように機能するのか説明してもらえますか? その回避策はありますか?スレッドが独立してメッセージを受信できるようにしたいと考えています。私のスレッドはすべてメインスレッドによって作成されます。これが理由でしょうか?

事前にご協力いただきありがとうございます。

マリウス。


Mghie、あなたはまったく正しかったです (最近、あなたは私にメッセージを送信するのを手伝ってくれました。覚えているかもしれません)。あなたが示唆したように、 GetMessage はすぐに戻りますが、実際にはメインウィンドウメソッドの呼び出しでスレッドがハングします:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
      if Assigned(FOnCommEventMethod) then
        FOnCommEventMethod(FCommEventsQueueItem);
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

FOnCommEventMethod はオブジェクトのメソッドであり、'procedure (EventMask: Cardinal) of object;' として宣言されています。(このスレッドはシリアル ポート イベントを処理します)。この場合、FOnCommEventMethod には、メイン フォーム クラスに属するプロシージャが割り当てられています。メソッドがスレッドによって呼び出されると、メイン スレッドが作業を終了するのを待ってスレッドがハングします。

どうして?ご覧のとおり、Synchronize() メソッドを使用してこのプロシージャを呼び出していません。したがって、スレッドがメインスレッドと同期しているとは思いません。それは暗黙のうちに起こりますか?ところで、メインのスレッド以外の他のスレッドからは GUI コンポーネントにアクセスしてはならないことを理解しているので、Synchronize メソッドを使用する必要がありますが、現在は簡単なテストを行っているだけです。

WaitForSingleObject の件名に戻ると、私はそれを使用すべきではないことを知っていますが、(偶然にも) 問題に気付いたおかげで、それは単なるテストでした。

ご協力いただきありがとうございます。あなたが私を助けてくれなかったら、私はおそらくメッセージを取り除き、代わりにイベントを使用するでしょう.そして最終的に、それが理由ではないことに気付くでしょう:-)。

4

3 に答える 3

3

メイン スレッドが作業を終了するか、Application.ProcessMessages メソッドが呼び出されたときにのみ、GetMessage が返され、スレッドが作業を開始します。

これが本当に起こっていることであるかどうかは疑わしい。私の知る限り、 SendMessage()のようなスレッドを同期する他の手段を使用しない限り、2 つのメッセージ ループは互いに独立している必要があります。スレッドが実際にGetMessage()の内部でブロックし、Synchronize() (内部でSendMessage()を使用している) の内部でブロックしていないことを確認していますか?

テストを実行するために、メイン スレッドで WaitForSingleObject 関数を使用し、イベントを数秒間待機しました。

メイン スレッドでWaitForSingleObject()を 100 ミリ秒よりも長いタイムアウトで使用しないでください。GUI の動作が遅くなるからです。実際、これは単にポーリングであるため、メインスレッドではまったく使用しないことをお勧めします。代わりに、ワーカー スレッドからメッセージを投稿してください。

于 2009-03-08T10:33:09.323 に答える