Как выполняется SendMessage из другого потока? - PullRequest
8 голосов
/ 31 мая 2010

Когда мы отправляем сообщение «, если указанное окно было создано вызывающим потоком, оконная процедура вызывается немедленно как подпрограмма ». Но «, если указанное окно было создано другим потоком, система переключается на этот поток и вызывает соответствующую оконную процедуру. Сообщения, передаваемые между потоками, обрабатываются только тогда, когда принимающий поток выполняет код поиска сообщения. » ( взято из документации 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, оно будет обработано перед любым другим опубликованным сообщением и будет отправлено непосредственно в оконную процедуру.

Ответы [ 3 ]

5 голосов
/ 01 июня 2010

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

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

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

Для дальнейшего ознакомления изучите раздел «Примечания» в записи MSDN PeekMessage.

1 голос
/ 31 мая 2010

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

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

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

1 голос
/ 31 мая 2010

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

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

Теперь ответ не полученспросить:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...