Wie wird eine SendMessage von einem anderen Thread ausgeführt?

8

Wenn wir eine Nachricht senden, " wenn das angegebene Fenster vom aufrufenden Thread erstellt wurde, wird die Fensterprozedur sofort als Subroutine " aufgerufen. Aber " wenn das angegebene Fenster von einem anderen Thread erstellt wurde, wechselt das System zu diesem Thread und ruft die entsprechende Fensterprozedur auf. Nachrichten, die zwischen Threads gesendet werden, werden nur verarbeitet, wenn der empfangende Thread Nachrichtenabrufcode ausführt. " (aus der MSDN-Dokumentation für SendMessage ).

Nun verstehe ich nicht wie (oder, besser gesagt, wenn ) die Ziel-Windows-Prozedur aufgerufen wird. Natürlich wird der Ziel-Thread nicht vorweggenommen (der Programmzähler wird nicht geändert). Ich nehme an, dass der Anruf während einiger Wartefunktion geschieht (wie GetMessage oder PeekMessage ), ist es wahr? Dieser Prozess ist irgendwo im Detail dokumentiert?

Update: Die Begründung dahinter wird durch das QS_SENDMESSAGE -Flag von GetQueueStatus() und MsgWaitForMultipleObjects() erklärt:

%Vor%

Dies bedeutet zusammen mit zusätzlichen Anmerkungen in der MSDN-Dokumentation, dass eine Nachricht, die von einem anderen Thread gesendet wurde, tatsächlich in die Warteschlange gestellt wird. Sobald GetMessage oder PeekMessage aufgerufen wird, wird es vor jeder anderen geposteten Nachricht verarbeitet, indem es direkt an die Fensterprozedur gesendet wird.

    
Wizard79 31.05.2010, 10:16
quelle

3 Antworten

5

Ich sehe hier einige Verwirrung.

Gemäß den MSDN-Dokumenten, wenn Sie die Nachrichtenwarteschlange des aktuellen Threads mit der Absicht der Nachrichtenverarbeitung berühren (z. B. wenn Sie PeekMessage oder GetMessage aufrufen), alle ausstehend gesendet ( dh nicht in die Warteschlange gestellte Nachrichten von anderen Threads werden behandelt - an die WndProc übergeben - und dann wird die Nachrichtenwarteschlange überprüft, also:

  • gesendete Nachrichten nie durchlaufen DispatchMessage und werden so schnell wie möglich bearbeitet:
    • im aktuellen Thread werden sie einfach an WndProc übergeben
    • in einem anderen Thread, werden sie vor jeder posted message processing
    • behandelt
  • Um mit gesendeten Nachrichten umgehen zu können, benötigt der Ziel-Thread immer noch eine Nachrichtenpumpe
  • PostThreadMessage macht genau das, was es angibt - posts eine Nachricht in einer Thread-Warteschlange - solche Nachrichten werden nicht an ein Fenster geleitet und müssen explizit behandelt werden
  • Die only Nachrichten, die von DispatchMessage verarbeitet werden, sind diejenigen, die von PostMessage oder einer Systemeinrichtung (Timer, Ereignisse, Benutzereingaben, etc.) erstellt wurden
  • Um Deadlocks zu vermeiden, verwenden Sie SendNotifyMessage , SendMessageTimeout oder SendMessageCallback anstelle von plain SendMessage zwischen verschiedenen Threads

Weitere Informationen finden Sie im Abschnitt "Bemerkungen" des Eintrags MSDN PeekMessage .

    
Viktor Svub 01.06.2010, 01:00
quelle
1

Kurze Antwort: Wenn der Ziel-Thread GetMessage (oder PeekMessage) gefolgt von DispatchMessage aufruft, wird die SendMessage vom anderen Thread empfangen und behandelt.

Ich bin nicht sicher, ob die empfangene SendMessage andere Nachrichten in der Warteschlange vorwegnimmt oder nicht. In beiden Fällen ist eine SendMessage von einem Thread zum anderen wie: "Veröffentlichen Sie diese Nachricht in der Nachrichtenwarteschlange des anderen Threads. Geben Sie diese zurück, wenn der Thread die Verarbeitung beendet hat".

Ein Jetzt für eine Antwort, nach der Sie nicht gefragt haben:

Wenn ich Interaktionen zwischen dem Haupt-UI-Thread und einem Arbeitsthread programmiere, versuche ich generell, die Verwendung von SendMessage zu vermeiden. Wenn Sie nicht vorsichtig sind, können Sie in eine Situation geraten, in der beide Threads gegeneinander festgefahren sind. (Stellen Sie sich den Fall vor, dass der Hauptthread WaitForSingleObject aufruft, damit der Worker-Thread abgeschlossen wird, der Worker-Thread jedoch bei SendMessage zurück zum UI-Thread blockiert wird.)

    
selbie 31.05.2010 10:29
quelle
1

Jedes Fenster ist mit einem Thread verknüpft. Sie können GetWindowThreadProcessId verwenden, um den Thread jedes Fensters abzurufen. Wenn Sie eine Nachricht an einen Windows-Server von einem anderen Thread in Bezug auf PostThreadMessage senden, wird die Nachricht in der Nachrichtenwarteschlange des Threads platziert. Der Thread muss eine get-message-Schleife haben (mit GetMessage zum Beispiel), um die Nachrichten zu erhalten und dort zur Fensterprozedur des Fensters zu senden.

Wenn Sie SendMessage statt PostThreadMessage aufrufen, rufen Sie die Windows-Prozedur direkt auf, ohne sie in die Nachrichtenwarteschlange zu stellen. Einige nicht in Warteschlangen eingereihte Nachrichten werden auch sofort an die Zielfensterprozedur gesendet, wobei die Systemnachrichtenwarteschlange und die Threadnachrichtenwarteschlange umgangen werden. (Siehe Ссылка ). Der Hauptgrund dafür, SendMessage anstelle von PostThreadMessage zu verwenden, wenn Sie Informationen von einem anderen Windows (Steuerelement) wie einen Text von einem anderen Steuerelement während der Verarbeitung einer anderen Nachricht lesen möchten. Sie sollten dies nur tun, wenn es wirklich benötigt wird. Also, wenn Sie SendMessage verwenden, um eine Nachricht an ein Fenster von einem anderen Thread zu senden, muss Ihr aktueller Thread für einige Zeit blockiert werden.

Es kann eine gute Idee sein, PostThreadMessage oder SendMessageCallback anstelle von SendMessage zu verwenden, wenn es möglich ist.

    
Oleg 31.05.2010 10:45
quelle

Tags und Links