Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > TThread.Queue для старых версий delphi


Автор: Чучмек 8.9.2013, 19:38
Вчера стала задача - выполнить определенное действие (процедура завершения) гарантированно после отработки потока.
Причем инициализация этого действия должна осуществляться из самого потока.
Посмотрев список методов TThread сразу нашел Queue.  Как Synchronize, только асинхронно.
Все ок, только вот когда потребовалось скомпилить в D7 (требование заказчика), то случилось вполне ожидаемое - нет в D7 у потоков такого метода.
Вот слепил  на скорую руку заглушку.
Может кому пригодится.
Код

unit TThreadPatch;

interface

uses
  forms,classes,windows,messages;

type
 TThread = class (classes.TThread)
 protected
   procedure Queue(AMethod: TThreadMethod);
 end;
implementation

const
  WM_QUEUE = WM_USER + $200;

type
  TMethodAsDWDW = record
     case Integer of
     1:(
        Method:TMethod;
        );
     2:(
        ThreadMethod:TThreadMethod;
        );
     3:(
        DW1,
        DW2:WPARAM
        );
   end;

{ TThread }

procedure TThread.Queue(AMethod: TThreadMethod);
var
  MethodAsDWDW:TMethodAsDWDW;
begin
  MethodAsDWDW.ThreadMethod:=AMethod;
  PostMessage(Application.Handle,WM_QUEUE,MethodAsDWDW.DW1,MethodAsDWDW.DW2);
end;



var
  ApplicationOldWNDPROC:function(HWND:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
function ApplicationWNDPROC(HWND:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
var
  MethodAsDWDW:TMethodAsDWDW;
begin
  if (HWND = Application.Handle) and (Msg = WM_QUEUE) then
  begin
    MethodAsDWDW.DW1:=wParam;
    MethodAsDWDW.DW2:=lParam;
    MethodAsDWDW.ThreadMethod;
  end;
  result:=ApplicationOldWNDPROC(HWND,Msg,wParam,lParam);
end;

initialization
  ApplicationOldWNDPROC:=Pointer(GetWindowLong(Application.Handle,GWL_WNDPROC));
  SetWindowLong(Application.Handle,GWL_WNDPROC,Integer(@ApplicationWNDPROC));
end.





Добавляем в uses после classes и все.

Автор: Poseidon 8.9.2013, 20:24
Цитата(Чучмек @  8.9.2013,  19:38 Найти цитируемый пост)
выполнить определенное действие (процедура завершения) гарантированно после отработки потока.
Не совсем ясна цель асинхронности, если все это нужно сделать после отработки потока. Как раз Synchronize или OnTerminate тут бы подошли не хуже Queue. Ну а что касается непосредственно Queue в ранних Delphi, то, помниться, там этот вопрос решался так же через PostMessage.

Автор: Чучмек 8.9.2013, 22:03
Цитата(Poseidon @  8.9.2013,  20:24 Найти цитируемый пост)
или OnTerminate

В том и дело, что OnTerminate вызывается через Synchronize.
Цитата

procedure TThread.DoTerminate;
begin
  if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;
 
А в вызываемом методе, в моем случае, стоит WaitFor.

Цитата

в моем случае
  
Мой случай - две кнопки. Одна создает поток, другая завершает. Плюс  у кнопок соответственно меняется enabled.
Но поток может завершится и "сам" - по ошибке. При "самостоятельном" завершении должен выполнится обработчик кнопки "стоп".
Как-то так.
Знаю. Можно было бы извернутся десятью другими способами.    

Автор: Poseidon 8.9.2013, 22:20
Цитата(Чучмек @  8.9.2013,  22:03 Найти цитируемый пост)
В том и дело, что OnTerminate вызывается через Synchronize.
Это верно, но это не имеет значения (в большинстве случаев) если речь идет о вызове после отработки потока.

Цитата(Чучмек @  8.9.2013,  22:03 Найти цитируемый пост)
в вызываемом методе, в моем случае, стоит WaitFor.
Вот при этому условии уже другой разговор. Тут явно нужна асинхронизация. Но если в этом твоем методе убрать WaitFor и засунуть его (метод) в OnTerminate, то, думаю, результат будет тот же.


Я не в коем случае не хочу раскритиковать твой код и сказать что это лажа. Код хороший. Другое дело в том, что ты наткнулся на проблему отсутствия в старом Delphi метода, которого там нет и (самое главное) без которого можно было бы вообще обойтись. Т.е. получилось так, что сам себе придумал сложность и попытался ее решить. Да, это похвально. Но правильнее было бы не натыкаться на такую сложность. Другими словами, ты показал общественности как можно решить вопрос отсутствия метода Queue в D7, я же хочу указать лишь на то, что конкретно в твоем случае нет особой нужды использовать этот метод. (Если честно, я вообще не понимаю смысла вызывать при завершении потока метод, который вызывает WaitFor этого потока. Используй OnTerminate, он гарантированно вызовется только при завершении потока. И не нужно ничего ждать вэйтвором). В другом же случае, где использование Queue было бы действительно оправдано, твой код может кому-то и пригодиться.  smile 

Автор: MetalFan 10.9.2013, 12:51
Цитата(Poseidon @  8.9.2013,  22:20 Найти цитируемый пост)
это не имеет значения (в большинстве случаев) если речь идет о вызове после отработки потока

полностью согласен. Не вижу смысла в пляске с бубном вокруг реализации Queue для D7 для данного случая.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)