Aquí hay un article from Delphi3000 que muestra cómo usar IOCP para crear un grupo de subprocesos. No soy el autor de este código, pero la información del autor está en el código fuente.
Estoy re-publicar los comentarios y código aquí:
Todo el mundo debe entender ahora por qué un hilo es, los principios de hilos y así sucesivamente. Para aquellos en necesidad, la función simple de un hilo es procesamiento separado de un hilo a otro, para permitir la ejecución simultánea y en paralelo. El principio principal de hilos es igual de simple, la memoria asignada que se hace referencia entre hilos se deben reunir para garantizar seguridad de acceso. Hay un número de otros principios, pero esto es realmente el que debe importar.
Y en ..
Un hilo de cola de seguro permitirá varios subprocesos para agregar y quitar, de inserción y extracción de los valores y de la cola con seguridad en un primer lugar en primer lugar base. Con una cola escrita eficiente y bien puede tener un componente muy útil en el desarrollo de aplicaciones con rosca , desde ayudar a con registro seguro de subprocesos, hasta procesamiento asincrónico de solicitudes.
un grupo de subprocesos es simplemente un hilo o un número de hilos que son la mayoría comúnmente utilizado para gestionar una cola de peticiones. Por ejemplo, un servidor web que tendría una cola continua de solicitudes que necesitan ser procesados uso agrupaciones de hebras para gestionar el http solicitudes, o una COM + o servidor DCOM utiliza un grupo de subprocesos para manejar la RPC peticiones. Esto se hace por lo que no es un menor impacto de la transformación de una petición a otro, por ejemplo si se ejecutó 3 peticiones de forma sincrónica y la primera solicitud tomó 1 minuto para completar, los segundo dos peticiones no completarían durante al menos 1 minuto agregando en la parte superior tiene tiempo para procesar, y para la mayoría de los clientes esto no es aceptable.
Entonces, ¿cómo hacer esto ..
A partir de la cola !!
Delphi hace proporciona un objeto TQUEUE cuales está disponible, pero es por desgracia no hilo de seguridad ni realmente muy eficiente, pero la gente debe buscar en el archivo a Contnrs.pas ver cómo Borland escritura hay pilas y colas . Solo hay dos funciones principales de requeridas para una cola, estas son add y remove/push y pop. Add/push agregará un valor, un puntero o un objeto al final de una cola. Y remove/pop eliminará y devolverá el primer valor en la cola.
Se podría derivar de TQUEUE objeto y anular los métodos protegidos y añadir en las secciones críticas, esto obtener una parte del camino, pero me que mi cola para esperar hasta que los nuevos solicitudes están en la cola y poner el subproceso en estado de reposo mientras espera nuevas solicitudes. Esto podría ser hecho al agregar en Mutexes o eventos de señalización , pero hay una manera más fácil. La aplicación de Windows proporciona una cola de finalización IO que nos proporciona el hilo de seguridad acceso seguro a una cola y un estado de mientras espera la nueva solicitud en la cola.
La implementación de la agrupación de hebras
La piscina hilo va a ser muy simple y gestionará x número de hilos deseados y pasar cada cola de solicitudes de a un evento proporcionado para ser procesado. Rara vez hay una necesidad de implementar una clase TThread y su lógica de para ser implementado y encapsulado dentro del evento ejecutar de la clase, por lo que un simple clase TSimpleThread se puede crear que ejecutará cualquier método de cualquier objeto dentro el contexto de otro hilo . Una vez que las personas entiendan esto, todo lo que necesita para preocuparse por se le asigna memoria.
Así es como se implementa.
TThreadQueue y TThreadPool aplicación
(* Implemented for Delphi3000.com Articles, 11/01/2004
Chris Baldwin
Director & Chief Architect
Alive Technology Limited
http://www.alivetechnology.com
*)
unit ThreadUtilities;
uses Windows, SysUtils, Classes;
type
EThreadStackFinalized = class(Exception);
TSimpleThread = class;
// Thread Safe Pointer Queue
TThreadQueue = class
private
FFinalized: Boolean;
FIOQueue: THandle;
public
constructor Create;
destructor Destroy; override;
procedure Finalize;
procedure Push(Data: Pointer);
function Pop(var Data: Pointer): Boolean;
property Finalized: Boolean read FFinalized;
end;
TThreadExecuteEvent = procedure (Thread: TThread) of object;
TSimpleThread = class(TThread)
private
FExecuteEvent: TThreadExecuteEvent;
protected
procedure Execute(); override;
public
constructor Create(CreateSuspended: Boolean; ExecuteEvent: TThreadExecuteEvent; AFreeOnTerminate: Boolean);
end;
TThreadPoolEvent = procedure (Data: Pointer; AThread: TThread) of Object;
TThreadPool = class(TObject)
private
FThreads: TList;
FThreadQueue: TThreadQueue;
FHandlePoolEvent: TThreadPoolEvent;
procedure DoHandleThreadExecute(Thread: TThread);
public
constructor Create(HandlePoolEvent: TThreadPoolEvent; MaxThreads: Integer = 1); virtual;
destructor Destroy; override;
procedure Add(const Data: Pointer);
end;
implementation
{ TThreadQueue }
constructor TThreadQueue.Create;
begin
//-- Create IO Completion Queue
FIOQueue := CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
FFinalized := False;
end;
destructor TThreadQueue.Destroy;
begin
//-- Destroy Completion Queue
if (FIOQueue <> 0) then
CloseHandle(FIOQueue);
inherited;
end;
procedure TThreadQueue.Finalize;
begin
//-- Post a finialize pointer on to the queue
PostQueuedCompletionStatus(FIOQueue, 0, 0, Pointer($FFFFFFFF));
FFinalized := True;
end;
(* Pop will return false if the queue is completed *)
function TThreadQueue.Pop(var Data: Pointer): Boolean;
var
A: Cardinal;
OL: POverLapped;
begin
Result := True;
if (not FFinalized) then
//-- Remove/Pop the first pointer from the queue or wait
GetQueuedCompletionStatus(FIOQueue, A, Cardinal(Data), OL, INFINITE);
//-- Check if we have finalized the queue for completion
if FFinalized or (OL = Pointer($FFFFFFFF)) then begin
Data := nil;
Result := False;
Finalize;
end;
end;
procedure TThreadQueue.Push(Data: Pointer);
begin
if FFinalized then
Raise EThreadStackFinalized.Create('Stack is finalized');
//-- Add/Push a pointer on to the end of the queue
PostQueuedCompletionStatus(FIOQueue, 0, Cardinal(Data), nil);
end;
{ TSimpleThread }
constructor TSimpleThread.Create(CreateSuspended: Boolean;
ExecuteEvent: TThreadExecuteEvent; AFreeOnTerminate: Boolean);
begin
FreeOnTerminate := AFreeOnTerminate;
FExecuteEvent := ExecuteEvent;
inherited Create(CreateSuspended);
end;
procedure TSimpleThread.Execute;
begin
if Assigned(FExecuteEvent) then
FExecuteEvent(Self);
end;
{ TThreadPool }
procedure TThreadPool.Add(const Data: Pointer);
begin
FThreadQueue.Push(Data);
end;
constructor TThreadPool.Create(HandlePoolEvent: TThreadPoolEvent;
MaxThreads: Integer);
begin
FHandlePoolEvent := HandlePoolEvent;
FThreadQueue := TThreadQueue.Create;
FThreads := TList.Create;
while FThreads.Count < MaxThreads do
FThreads.Add(TSimpleThread.Create(False, DoHandleThreadExecute, False));
end;
destructor TThreadPool.Destroy;
var
t: Integer;
begin
FThreadQueue.Finalize;
for t := 0 to FThreads.Count-1 do
TThread(FThreads[t]).Terminate;
while (FThreads.Count > 0) do begin
TThread(FThreads[0]).WaitFor;
TThread(FThreads[0]).Free;
FThreads.Delete(0);
end;
FThreadQueue.Free;
FThreads.Free;
inherited;
end;
procedure TThreadPool.DoHandleThreadExecute(Thread: TThread);
var
Data: Pointer;
begin
while FThreadQueue.Pop(Data) and (not TSimpleThread(Thread).Terminated) do begin
try
FHandlePoolEvent(Data, Thread);
except
end;
end;
end;
end.
Como se puede ver que es bastante recta hacia adelante, y con esto se puede aplicar muy fácilmente ninguna cola de solicitudes sobre las roscas y realmente cualquier tipo de requisito que requiera puede hacerse usando estos objeto ys Le ofrecemos mucho tiempo y esfuerzo .
Usted puede usar esto para cola las solicitudes de un subproceso a múltiples hilos, o cola de peticiones de múltiples hilos abajo a un hilo que hace que este una solución bastante agradable.
Aquí hay algunos ejemplos del uso de estos objetos .
Tema tala segura
para permitir que varios hilos para escribir de forma asíncrona a un archivo de registro .
uses Windows, ThreadUtilities,...;
type
PLogRequest = ^TLogRequest;
TLogRequest = record
LogText: String;
end;
TThreadFileLog = class(TObject)
private
FFileName: String;
FThreadPool: TThreadPool;
procedure HandleLogRequest(Data: Pointer; AThread: TThread);
public
constructor Create(const FileName: string);
destructor Destroy; override;
procedure Log(const LogText: string);
end;
implementation
(* Simple reuse of a logtofile function for example *)
procedure LogToFile(const FileName, LogString: String);
var
F: TextFile;
begin
AssignFile(F, FileName);
if not FileExists(FileName) then
Rewrite(F)
else
Append(F);
try
Writeln(F, DateTimeToStr(Now) + ': ' + LogString);
finally
CloseFile(F);
end;
end;
constructor TThreadFileLog.Create(const FileName: string);
begin
FFileName := FileName;
//-- Pool of one thread to handle queue of logs
FThreadPool := TThreadPool.Create(HandleLogRequest, 1);
end;
destructor TThreadFileLog.Destroy;
begin
FThreadPool.Free;
inherited;
end;
procedure TThreadFileLog.HandleLogRequest(Data: Pointer; AThread: TThread);
var
Request: PLogRequest;
begin
Request := Data;
try
LogToFile(FFileName, Request^.LogText);
finally
Dispose(Request);
end;
end;
procedure TThreadFileLog.Log(const LogText: string);
var
Request: PLogRequest;
begin
New(Request);
Request^.LogText := LogText;
FThreadPool.Add(Request);
end;
ya que este es el registro en un archivo que se proceso de todas las solicitudes a un solo hilo, pero que podría ser rica correo electrónico notificaciones con un mayor número de hilos , o mejor aún, proceso perfil con lo que está pasando o pasos en su programa que voy a demostrar en otro artículo como este uno tiene bastante tiempo ahora.
Por ahora te dejo con esto, disfruta .. Deja un comentario si hay cualquier cosa que la gente tenga.
Chris
tengo una herramienta similar. es solo un montón de hilos esperando respuestas de eco ICMP. –
Si saca suficientes pings, activará los sistemas de detección de intrusos. –