Creo que la mejor solución es utilizar un subproceso de grupo de subprocesos para realizar el trabajo.
- asignar una unidad de trabajo para consultar los atributos de un archivo
- vamos
GetFileAttributes
se termina de ejecutar
- enviar los resultados de vuelta a su forma
- cuando su función rosca completa, el hilo vuelve automáticamente al grupo (no es necesario que lo mate)
Al usar el grupo de subprocesos, ahorra los costos de crear nuevos subprocesos.
Y guardas la miseria de tratar de deshacerte de ellos.
entonces usted tiene su método de ayuda práctica que funciona procedimiento de método de un objeto en un hilo de rosca de la piscina usando QueueUserWorkItem
:
RunInThreadPoolThread(
GetFileAttributesThreadMethod,
TGetFileAttributesData.Create('D:\temp\foo.xml', Self.Handle),
WT_EXECUTEDEFAULT);
de crear el objeto de mantener la información de datos de rosca:
TGetFileAttributesData = class(TObject)
public
Filename: string;
WndParent: HWND;
Attributes: DWORD;
constructor Create(Filename: string; WndParent: HWND);
end;
y crear su método de devolución de llamada de rosca:
procedure TForm1.GetFileAttributesThreadMethod(Data: Pointer);
var
fi: TGetFileAttributesData;
begin
fi := TObject(Data) as TGetFileAttributesData;
if fi = nil then
Exit;
fi.attributes := GetFileAttributes(PWideChar(fi.Filename));
PostMessage(fi.WndParent, WM_GetFileAttributesComplete, NativeUInt(Data), 0);
end;
t gallina que acaba de tratar el mensaje:
procedure WMGetFileAttributesComplete(var Msg: TMessage); message WM_GetFileAttributesComplete;
procedure TfrmMain.WMGetFileAttributesComplete(var Msg: TMessage);
var
fi: TGetFileAttributesData;
begin
fi := TObject(Pointer(Msg.WParam)) as TGetFileAttributesData;
try
ShowMessage(Format('Attributes of "%s": %.8x', [fi.Filename, fi.attributes]));
finally
fi.Free;
end;
end;
La mágica RunInThreadPoolThread
es sólo un poco de pelusa que le permite ejecutar un método de instancia en un hilo:
Cuál es sólo un envoltorio que le permite llamar método en un variable de instancia:
TThreadMethod = procedure (Data: Pointer) of object;
TThreadPoolCallbackContext = class(TObject)
public
ThreadMethod: TThreadMethod;
Context: Pointer;
end;
function ThreadPoolCallbackFunction(Parameter: Pointer): Integer; stdcall;
var
tpContext: TThreadPoolCallbackContext;
begin
try
tpContext := TObject(Parameter) as TThreadPoolCallbackContext;
except
Result := -1;
Exit;
end;
try
tpContext.ThreadMethod(tpContext.Context);
finally
try
tpContext.Free;
except
end;
end;
Result := 0;
end;
function RunInThreadPoolThread(const ThreadMethod: TThreadMethod; const Data: Pointer; Flags: ULONG): BOOL;
var
tpContext: TThreadPoolCallbackContext;
begin
{
Unless you know differently, the flag you want to use is 0 (WT_EXECUTEDEFAULT).
If your callback might run for a while you can pass the WT_ExecuteLongFunction flag.
Sure, I'm supposed to pass WT_EXECUTELONGFUNCTION if my function takes a long time, but how long is long?
http://blogs.msdn.com/b/oldnewthing/archive/2011/12/09/10245808.aspx
WT_EXECUTEDEFAULT (0):
By default, the callback function is queued to a non-I/O worker thread.
The callback function is queued to a thread that uses I/O completion ports, which means they cannot perform
an alertable wait. Therefore, if I/O completes and generates an APC, the APC might wait indefinitely because
there is no guarantee that the thread will enter an alertable wait state after the callback completes.
WT_EXECUTELONGFUNCTION (0x00000010):
The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.
WT_EXECUTEINPERSISTENTTHREAD (0x00000080)
The callback function is queued to a thread that never terminates.
It does not guarantee that the same thread is used each time. This flag should be used only for short tasks
or it could affect other timer operations.
This flag must be set if the thread calls functions that use APCs.
For more information, see Asynchronous Procedure Calls.
Note that currently no worker thread is truly persistent, although worker threads do not terminate if there
are any pending I/O requests.
}
tpContext := TThreadPoolCallbackContext.Create;
tpContext.ThreadMethod := ThreadMethod;
tpContext.Context := Data;
Result := QueueUserWorkItem(ThreadPoolCallbackFunction, tpContext, Flags);
end;
ejercicio para el lector: Crear un Cancelado bandera dentro del objeto GetFileAttributesData
que dice º e hilo que es debe liberar el objeto de datos y no publicar un mensaje para el padre.
Es todo un largo camino de decir que está creando:
DWORD WINAPI GetFileAttributes(
_In_ LPCTSTR lpFileName,
_Inout_ LPOVERLAPPED lpOverlapped,
_In_ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
puedo pensar en cualquier cosa excepto el modelo asíncrono. –
En otras circunstancias, he resuelto este problema mediante la implementación de un servidor web minimalista para servir los archivos compartidos, ya que una solicitud HTTP puede cancelarse o sincronizarse fácilmente. Pero en este caso, esta no es la solución por una variedad de razones (dolores de cabeza de implementación, problemas de seguridad, etc.). –