Как я могу реализовать цикл сообщений в потоке с использованием OTL? Application.ProcessMessages; это то, что я использовал до сих пор, но это не очень безопасно использовать.
Спасибо
Как я могу реализовать цикл сообщений в потоке с использованием OTL? Application.ProcessMessages; это то, что я использовал до сих пор, но это не очень безопасно использовать.
Спасибо
Вот как я вытягиваю сообщения из очереди потоков:
while GetMessage(Msg, 0, 0, 0) and not Terminated do begin
Try
TranslateMessage(Msg);
DispatchMessage(Msg);
Except
Application.HandleException(Self);
End;
end;
Использование Application.ProcessMessages
приведет к вытаскиванию сообщений очереди вызывающего потока. Но он не подходит для использования в цикле сообщений, потому что он не будет блокироваться. Вот почему вы используете GetMessage
. Он блокирует, если очередь пуста. И Application.ProcessMessages
также вызывает другие методы TApplication
, которые не предназначены для потокобезопасности. Поэтому есть множество причин не называть его нитью, кроме основного потока.
Когда вам нужно завершить поток, я делаю это:
Terminate;
PostThreadMessage(ThreadID, WM_NULL, 0, 0);
//wake the thread so that it can notice that it has terminated
Ни один из них не является специфичным для OTL. Этот код предназначен для жизни в потоке TThread
. Однако идеи могут быть переданы.
В комментариях указывается, что вы хотите запустить занятый, неблокирующий цикл сообщений. Вы использовали бы PeekMessage
для этого.
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin
Try
TranslateMessage(Msg);
DispatchMessage(Msg);
Except
Application.HandleException(Self);
End;
end;
Вы можете создать цикл, аналогичный циклу в Application.Run.
Вы можете вызвать PeekMessage
, который проверяет наличие сообщения. PeekMessage проверяет очередь сообщений текущего потока, поэтому, если вы используете его в своем потоке, он проверяет очередь сообщений в потоке (на который вы можете отправлять сообщения с помощью PostThreadMessage).
Вместо PeekMessage вы также можете использовать GetMessage
, который ждет, пока не будет получено сообщение. GetMessage
возвращает 0 возвращает false
. *)
когда он получает сообщение WM_QUIT
, которое также является сигналом для завершения цикла сообщения. После этого рискованно вызвать GetMessage, так как он может не получить другое сообщение, и это может помешать вашему приложению нормально закрыться, поскольку оно блокируется.
Application.ProcessMessages действительно не очень безопасно, потому что он выполняет множество дополнительных функций, характерных для основного потока. Во-первых, он запускает Application.OnIdle, как только очередь сообщений пуста, что означает, что она вызывает это (проблема 1), когда очередь сообщений потока пуста и (проблема 2) в контексте потока, не позволяя VCL в этом случае.
* ) О возвращаемом значении GetMessage: я заметил, что Delphi реализует GetMessage как возвращающий LongBool. Однако фактическое возвращаемое значение является целым числом. Он возвращает 0 в случае WM_QUIT, -1 в случае ошибки и ненулевое значение в других случаях. Microsoft заявляет:
Поскольку возвращаемое значение может быть отличным от нуля, ноль или -1, избегайте использования кода, например это:
while (GetMessage( lpMsg, hWnd, 0, 0)) ...
К сожалению, вам нужно будет импортировать GetMessage под другим псевдонимом, чтобы использовать его правильно.