Pregunta AsyncCall con Delphi 2007


Lo que básicamente quiero es comenzar AsyncCall y proceda con la carga de mi código. Tengo la sección Interfaz que consume mucho tiempo (600 ms) y quiero cargar este código en hilo independiente.

He intentado usar AsyncCall para hacer algo como esto:

procedure Load;
begin
...
end;

initialization
  AsyncCall(@Load, []); // or LocalAsyncCall(@Load)

Sin embargo, esto Load El procedimiento realmente comienza en el hilo principal y no en el nuevo hilo creado. ¿Cómo puedo forzar la Load procedimiento para ser cargado en cualquier hilo que no sea MainThread?

Puedo crear TThread y Execute esto, pero quiero forzar AsyncCall o LocalAsyncCall o cualquier cosa de AsyncCall biblioteca para hacer trabajar.

Gracias por tu ayuda.


10
2018-01-10 19:18


origen


Respuestas:


El problema es que su código no conserva el IAsyncCall interfaz que es devuelta por el AsyncCall función.

AsyncCall(@Load, []);
//AsyncCall returns an IAsyncCall interface,
//but this code does not take a reference to it

Debido a esto, la interfaz que se devuelve tiene su recuento de referencia decrementado a cero tan pronto como se completa la sección de inicialización. Por lo tanto, libera el objeto que implementa la interfaz que hace esto:

destructor TAsyncCall.Destroy;
begin
  if FCall <> nil then
  begin
    try
-->   FCall.Sync; // throw raised exceptions here
    finally
      FCall.Free;
    end;
  end;
  inherited Destroy;
end;

La línea clave es la llamada a Sync que obliga a que la llamada asíncrona se ejecute hasta su finalización. Todo esto sucede en el hilo principal que explica el comportamiento que informa.


La solución es que simplemente necesitas mantener el IAsyncCall interfaz viva al almacenarla en una variable.

var
  a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);

En el código real, debes asegurarte de que Load había completado antes de ejecutar cualquier código que depende de Load. Cuando su programa llegó a un punto donde requería Load haber sido llamado tiene que llamar Sync sobre el IAsyncCall interfaz.

Entonces podrías escribir algo como esto.

unit MyUnit;

interface

procedure EnsureLoaded;

implementation

uses
  AsyncCalls;

....

procedure Load;
begin
  ....
end;

var
  LoadAsyncCall: IAsyncCall;

procedure EnsureLoaded;
begin
  LoadAsyncCall := nil;//this will effect a call to Sync
end;

initialization
  LoadAsyncCall := AsyncCall(@Load, []);

end.

La llamada EnsureLoaded de otras unidades que requirieron Load haber corrido O, alternativamente, llame EnsureLoaded de cualquier método exportado por MyUnit eso dependía de Load habiendo corrido La última opción tiene una encapsulación mucho mejor.


5
2018-01-10 20:11



¿Has intentado algo como ésto?:

procedure Load;
begin
  if GetCurrentThreadId <> MainThreadID then
    Beep;
end;

var a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);
  a.ForceDifferentThread;

ForceDifferentThread () le dice a AsyncCalls que la función asignada debe         no se ejecutará en el hilo actual.


8
2018-01-10 22:15