В моем приложении 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)).
Только когда основной поток завершает свою работу или вызывается метод Application.ProcessMessages, GetMessage возвращает результат, и мой поток начинает выполнять свою работу. Реализуя этот вид межпотоковой связи, я был уверен, что мои потоки будут работать независимо, и я никогда не ожидал, что получение сообщений, отправленных непосредственно в поток, будет зависеть от основного потока.
Выполняя тесты, я использовал функцию WaitForSingleObject в главном потоке, ожидая события в течение нескольких секунд. Это когда я заметил, что мой поток не делал никакой работы, даже если сообщения были отправлены ему другим потоком. Когда функция WaitForSingleObject наконец-то закончила ожидание и основной поток перестал работать, функция GetMessage в моем потоке вернулась.
Может кто-нибудь объяснить мне, почему это так работает? Есть ли обходной путь к этому? Я бы хотел, чтобы моя тема получала сообщения самостоятельно. Все мои темы созданы основным потоком. Может ли это быть причиной?
Заранее спасибо за помощь.
Мариуш.
Mghie, вы снова были абсолютно правы (вы, возможно, помните меня в последнее время с сообщениями). Как вы и предлагали, 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 - это метод объекта, объявленный как 'процедура (EventMask: Cardinal) объекта;' (этот поток обрабатывает события последовательного порта). В этом случае FOnCommEventMethod была назначена процедура, принадлежащая к основному классу формы. Когда метод вызывается моим потоком, поток зависает, ожидая, пока основной поток завершит свою работу.
Как получилось? Как видите, я не использую метод Synchronize () для вызова этой процедуры. Поэтому я не ожидал, что мой поток будет синхронизироваться с основным потоком. Это происходит неявно? Кстати, я понимаю, что к любым компонентам графического интерфейса не должны обращаться никакие другие потоки, кроме основного, поэтому следует использовать метод Synchronize, но сейчас я делаю только несколько быстрых тестов.
Возвращаясь к теме WaitForSingleObject, я знаю, что не должен ее использовать, но это был всего лишь тест, благодаря которому (по совпадению) я заметил проблему.
Спасибо за вашу помощь. Если бы вы не помогли мне, я, вероятно, избавился бы от сообщений и использовал бы вместо этого события, и, наконец, заметил бы, что это не было причиной: -).