Как выполняется SendMessage от другого потока?

Когда мы отправляем сообщение, "если указанное окно было создано вызывающим потоком, оконную процедуру сразу называют как подпрограмма". Но, "если указанное окно было создано другим потоком, система переключается на тот поток и называет соответствующую оконную процедуру. Сообщения, отправленные между потоками, обрабатываются только, когда поток получения выполняет код извлечения сообщений". (взятый из документации MSDN для SendMessage).

Теперь, я не понимаю, как (или, более соответственно, когда) целевую процедуру окон называют. Конечно, целевой поток не будет вытеснен (счетчик команд не изменяется). Я предполагаю, что вызов произойдет во время некоторых, ожидают функция (как GetMessage или PeekMessage), это верно? Тот процесс документируется подробно где-нибудь?


Обновление: объяснение позади него объяснено QS_SENDMESSAGE флаг GetQueueStatus() и MsgWaitForMultipleObjects():

QS_SENDMESSAGE
 A message sent by another thread or application is in the queue.

Это, наряду с дополнительными комментариями в документации MSDN, означает, что сообщение, отправленное другим потоком, на самом деле добавлено очереди. Затем как только GetMessage или PeekMessage названы, это будет обработано перед любым другим добавленным сообщением, будучи отправленным непосредственно в оконную процедуру.

9
задан lornova 14 June 2010 в 09:16
поделиться

3 ответа

Я вижу здесь некоторую путаницу.

Согласно документации MSDN, когда вы касаетесь очереди сообщений текущего потока с целью обработки сообщения (например, если вы вызываете PeekMessage или GetMessage ), все ожидающие отправленные (т.е. не поставленные в очередь) сообщения из других потоков обрабатываются - передаются в WndProc - а затем проверяется очередь сообщений, поэтому:

  • отправленные сообщения никогда проходят через DispatchMessage и обрабатываются при первой возможности:
    • в текущем потоке они просто передаются в WndProc
    • в другом потоке, они обрабатываются перед любой обработкой отправленных сообщений
  • , чтобы иметь возможность обрабатывать отправленные сообщения, целевой поток по-прежнему нуждается в перекачке сообщений
  • PostThreadMessage делает именно то, что заявляет - отправляет сообщение в очередь потоков - такие сообщения не направляются ни в какое окно и должны обрабатываться явно
  • только сообщения, обрабатываемые DispatchMessage , создаются PostMessage или некоторыми системными средствами (таймеры, события, ввод данных пользователем и т. д.)
  • , чтобы избежать взаимоблокировок используйте SendNotifyMessage , SendMessageTimeout или SendMessageCallback вместо обычного SendMessage между разными потоками

. запись MSDN PeekMessage .

6
ответ дан 4 December 2019 в 22:27
поделиться

Каждое окно связано с потоком. Вы можете использовать GetWindowThreadProcessId для получения потока каждого окна. Если вы посылаете сообщение окну из другого потока с помощью PostThreadMessage, сообщение будет помещено в очередь сообщений потока. Поток должен иметь цикл get-message (например, с GetMessage), чтобы получать сообщения и отправлять их в оконную процедуру окна.

Если вы вызываете SendMessage вместо PostThreadMessage, вы вызываете процедуру окна напрямую, не помещая ее в очередь сообщений. Некоторые сообщения, не занесенные в очередь, также сразу отправляются в целевую оконную процедуру, минуя системную очередь сообщений и очередь сообщений потока. (см. http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages). Основная причина использовать SendMessage вместо PostThreadMessage, если вы хотите передать некоторую информацию из другого окна (элемента управления), например, прочитать текст из другого элемента управления во время обработки другого сообщения. Вы должны делать это только в том случае, если это действительно необходимо. Так, если вы используете SendMessage для отправки сообщения окну из другого потока, ваш текущий поток должен быть заблокирован на некоторое время.

Может быть хорошей идеей использовать PostThreadMessage или SendMessageCallback вместо SendMessage, если это возможно.

1
ответ дан 4 December 2019 в 22:27
поделиться

Короткий ответ: Когда целевой поток вызывает GetMessage (или PeekMessage), за которым следует DispatchMessage, то SendMessage от другого потока принимается и обрабатывается.

Я не уверен, вытесняет ли полученное SendMessage другие сообщения в очереди или нет. В любом случае, SendMessage от одного потока к другому - это все равно, что сказать: "Помести это сообщение в очередь сообщений другого потока. Вернись, когда этот поток закончит его обработку".

А теперь ответ, о котором вы не спрашивали:

Вообще, когда я программирую взаимодействие между основным потоком пользовательского интерфейса и рабочим потоком, я стараюсь избегать использования SendMessage. Если вы не будете осторожны, вы можете попасть в ситуацию, когда оба потока заблокируют друг друга. (Вспомните случай, когда основной поток вызывает WaitForSingleObject, чтобы дождаться завершения рабочего потока, но рабочий поток заблокирован на SendMessage обратно в поток UI).

1
ответ дан 4 December 2019 в 22:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: