Вопрос

В моем приложении 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)).

Только когда основной поток завершает свою работу или приложение.Вызывается метод ProcessMessages, возвращается GetMessage, и мой поток начинает выполнять свою работу.Реализуя этот вид межпотоковой связи, я был уверен, что мои потоки будут работать независимо, и я бы никогда не ожидал, что прием сообщений, отправленных непосредственно в поток, будет зависеть от основного потока.

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

Может ли кто-нибудь объяснить мне, почему это работает именно так?Есть ли обходной путь для этого?Я хотел бы, чтобы мой поток получал сообщения независимо.Все мои потоки создаются основным потоком.Может ли это быть причиной?

Заранее благодарю за вашу помощь.

Mariusz.


Меги, ты снова был абсолютно прав (возможно, ты помнишь, что в последнее время ты помогал мне с сообщениями).Как вы предположили, 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 (маска события:Кардинальный) объекта;' (этот поток обрабатывает события последовательного порта).В этом случае методу foncommevent была назначена процедура, принадлежащая к основному классу form.Когда метод вызывается моим потоком, поток зависает, ожидая, пока основной поток завершит свою работу.

Как так вышло?Как вы можете видеть, я не использую метод Synchronize() для вызова этой процедуры.Поэтому я бы не ожидал, что мой поток будет синхронизироваться с основным потоком.Происходит ли это неявно?Кстати, я понимаю, что к любым компонентам GUI не должны быть доступны никакие другие потоки, кроме основного, поэтому следует использовать метод Synchronize , но сейчас я делаю только несколько быстрых тестов.

Возвращаясь к теме WaitForSingleObject, я знаю, что мне не следует ее использовать, но это был всего лишь тест, благодаря которому (по совпадению) Я заметил проблему.

Спасибо за вашу помощь.Если бы вы мне не помогли, я бы, вероятно, избавился от обмена сообщениями и вместо этого использовал события, и, наконец, я бы заметил, что это не было причиной :-).

Это было полезно?

Решение

Только когда основной поток завершает свою работу или приложение.Вызывается метод ProcessMessages, возвращается GetMessage, и мой поток начинает выполнять свою работу.

Я сомневаюсь, что это действительно то, что происходит.AFAIK два цикла обмена сообщениями должны быть независимы друг от друга, до тех пор, пока вы не используете другие средства синхронизации потоков, такие как Отправить сообщение().Вы уверены, что поток действительно блокируется внутри GetMessage() Получить сообщение() и не внутри Синхронизировать() (который использует Отправить сообщение() внутренне)?

Выполняя тесты, я использовал функцию WaitForSingleObject в основном потоке, ожидая события в течение нескольких секунд.

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

Другие советы

Вы можете создать очередь сообщений для своего потока.Просто выполните следующий код в вашем потоке:

MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
SetEvent(messageQueueReady);
while (GetMessage(&msg, NULL, 0, 0)) 
{
    ...// do message processing here
}

Вызов PeekMessage заставляет операционную систему создать новую очередь сообщений для вашего потока.Вы должны убедиться, что это синхронизировано, т. е.вы должны подождать (например,через WaitForSingleObject) для успешного выполнения вызова перед отправкой сообщений в этот поток (напримерчерез PostThreadMessage).Вот почему в приведенном выше примере есть вызов SetEvent API.

Редактировать: Извините, что пример приведен на C, надеюсь, для вас это нормально.

Видишь http://groups.google.com/group/borland.public.delphi.language .delphi.win32/browse_thread/поток/cf368834a606321b

Запрошенная дистилляция, опуская множество грубых деталей, в которых скрывается дьявол:основной поток (или VCL) является особенным в Delphi, потому что многие вещи под капотом не являются потокобезопасными, и он владеет ими всеми.Такие вещи, как цикл сообщений, заканчиваются ожиданием из-за вещей, которые синхронизируются с потоком VCL под капотом.У многих людей есть теории на этот счет.То, что, кажется, работает лучше всего, - это сделать ваш поток VCL как можно более легким и отзывчивым, чтобы свести к минимуму ожидания.Все в значительной степени согласны с этим.У некоторых людей есть идеи о других вещах, которые могли бы сработать, но другие люди думают, что они просто напрашиваются на неприятности.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top