Autoestar un hilo en Delphi cuando no es necesario y reanudando de forma segura
-
25-09-2019 - |
Pregunta
Esta pregunta involucra a Delphi y Xe específicamente despreciando suspender y reanudar. He leído otras publicaciones y no he encontrado un uso similar hasta ahora, así que voy a seguir adelante y pedir una discusión.
Lo que me gustaría saber es una mejor manera de detener un hilo cuando no es necesario.
Tenemos una clase de Delphi que hemos usado durante años que es básicamente una cola FIFO que está asociada con un proceso roscado. La cola acepta un objeto de datos en el hilo principal y si el hilo está suspendido, lo reanudará.
Como parte del proceso de ejecución del hilo, el objeto sale de la cola y se procesa en el hilo. Por lo general, esto es para hacer una búsqueda de base de datos.
Al final del proceso, una propiedad del objeto se actualiza y se marca como está disponible para el hilo principal o se pasa a otra cola. El último (bueno, realmente es el primer) paso del proceso de ejecución es verificar si hay más elementos en la cola. Si lo existe, continúa, de lo contrario se suspende a sí mismo.
La clave es que la única acción de suspensión está dentro del bucle de ejecución cuando se completa, y el único currículum durante las operaciones normales se llama cuando se coloca un nuevo elemento en la cola. La excepción es cuando se termina la clase de cola.
La función de currículum se parece a esto.
process TthrdQueue.MyResume();
begin
if Suspended then begin
Sleep(1); //Allow thread to suspend if it is in the process of suspending
Resume();
end;
end;
La ejecución se parece a esto
process TthrdQueue.Execute();
var
Obj : TMyObject;
begin
inherited;
FreeOnTerminate := true;
while not terminated do begin
if not Queue.Empty then begin
Obj := Pop();
MyProcess(Obj); //Do work
Obj.Ready := true;
end
else
Suspend(); // No more Work
end; //Queue clean up in Destructor
end;
La rutina de empuje Tthrdqueue llama a MyResume después de agregar otro objeto en la pila. Myresume solo llama al currículum si el hilo está suspendido.
Al apagar, configuramos terminando a True y llame a MyResume si está suspendido.
Solución
Recomendaría la siguiente implementación de Tthrdqueue:
type
TthrdQueue = class(TThread)
private
FEvent: THandle;
protected
procedure Execute; override;
public
procedure MyResume;
end;
implementation
procedure TthrdQueue.MyResume;
begin
SetEvent(FEvent);
end;
procedure TthrdQueue.Execute;
begin
FEvent:= CreateEvent(nil,
False, // auto reset
False, // initial state = not signaled
nil);
FreeOnTerminate := true;
try
while not Terminated do begin
if not Queue.Empty then begin
Obj := Pop();
MyProcess(Obj); //Do work
Obj.Ready := true;
end
else
WaitForSingleObject(FEvent, INFINITE); // No more Work
end;
finally
CloseHandle(FEvent);
end;
end;
Otros consejos
En lugar de suspender el hilo, hazlo dormir. Haga que bloquee un mango esperable, y cuando el mango se indique, el hilo se despertará.
Tiene muchas opciones para objetos esperables, incluidos eventos, objetos mutex, semáforos, colas de mensajes, tuberías.
Supongamos que elige usar un evento. Haz que sea un evento de reinicio automático. Cuando la cola esté vacía, llame al evento WaitFor
método. Cuando algo más puega la cola o quiera dejar de fumar, haga que llame al evento SetEvent
método.
Preferí la técnica es usar la cola de mensajes del sistema operativo. Reemplazaría su objeto de cola con mensajes. Entonces, escriba un estándar GetMessage
círculo. Cuando la cola está vacía, se bloqueará automáticamente para esperar un nuevo mensaje. Convierta una solicitud de terminación en solo otro mensaje. (Los TThread.Terminate
El método simplemente no es una función muy útil una vez que comienzas a hacer algo interesante con los hilos porque no es virtual).
Hay una biblioteca para permitir la implementación de la cola de consumidor de productores en Delphi usando variables de condición. Este escenario es en realidad el ejemplo discutido.
El ejemplo clásico de las variables de condición es el problema del productor/consumidor. Uno o más hilos llamados productores producen elementos y los agregan a una cola. Los consumidores (otros hilos) consumen artículos eliminando los artículos producidos de la cola.