2010-12-09 33 views
5

Esta pregunta involucra a Delphi y XE específicamente desaprobatorio Suspender y reanudar. He leído otras publicaciones y hasta ahora no he encontrado un uso similar, así que voy a seguir adelante y solicitar una discusión.Auto Suspendiendo un hilo en Delphi cuando no es necesario y reanudando de manera segura

Lo que me gustaría saber es si hay una mejor manera de pausar un hilo cuando no es necesario?

Tenemos una clase Delphi que hemos utilizado durante años, que es básicamente una cola FIFO que está asociada a un proceso enhebrado. La cola acepta un objeto de datos en el hilo principal y si el hilo se suspende, lo reanudará.

Como parte del proceso Ejecutar del subproceso, el objeto se saca de la cola y se procesa en el subproceso. Por lo general, esto es hacer una búsqueda en la base de datos.

Al final del proceso, una propiedad del objeto se actualiza y se marca como 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 comprobar si hay más elementos en la cola. Si hay continúa, de lo contrario se suspende.

La clave es la única acción de suspensión dentro del ciclo de ejecución cuando se completa, y se invoca el único resumen durante las operaciones normales cuando se coloca un nuevo elemento en la cola. La excepción es cuando la clase de cola se termina.

La función de reanudación se ve más o menos así.

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 es similar 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; 

El TthrdQueue Empuje llamadas de rutina MyResume después de añadir otro objeto en la pila. MyResume solo llama a Reanudar si el hilo está suspendido.

Al apagar establecemos terminar en verdadero y llamar a MyResume si se suspende.

+0

No soy un experto pero simplemente utilizaría Sleep (250) o SignalObjectAndWait (ver msdn) para un control más exacto. –

Respuesta

5

lo recomiendo 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; 
+2

Mencionó que está en Delphi XE, por lo que ya tiene acceso a la clase genérica TThreadedQueue en la unidad Generics.Collections. TThreadedQueue es una cola FIFO con la capacidad de sincronizar subprocesos mientras se presiona y aparece. – vcldeveloper

+1

Todavía admitimos una gran cantidad de código Delphi 7 en nuestras bibliotecas. Pero voy a ver TThreadedQueue para futuros endevours. Me gusta la solución dada por su facilidad para actualizar nuestro código existente. –

+0

Parece una buena solución, pero ¿cuándo vas a llamar a MyResume? ¿Hará la cola eso? ¿Y cuando? ¿Cómo sabe qué hilos despertar? ¿O simplemente despertaría todos los hilos dormidos tan pronto como se agregue un elemento en la parte posterior de la cola? – GolezTrol

3

En lugar de suspender el hilo, lo convierten en el sueño. Haz que se bloquee en algún identificador que se pueda usar, y cuando se mande el identificador, el hilo se activará.

usted tiene muchas opciones para los objetos de temporizador de espera, como actos, objetos mutex, semáforos, colas de mensajes, tuberías.

Supongamos que elige utilizar un evento. Haz que sea un evento de restablecimiento automático. Cuando la cola está vacía, llame al método WaitFor del evento. Cuando algo más rellene la cola o quiera abandonar, haga que llame al método SetEvent del evento.

La técnica preferida es utilizar la cola de mensajes del sistema operativo. Reemplazaría tu cola con mensajes. Luego, escriba un ciclo estándar GetMessage. 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. (El método TThread.Terminate simplemente no es una función muy útil una vez que comienzas a hacer algo interesante con hilos porque no es virtual.)

+0

Veo lo que quiere decir usar Windows para soportar las colas. Lo que hemos estado usando está en muchos códigos existentes y por ahora es lo suficientemente bueno. Pero definitivamente lo investigaré para el trabajo futuro, me gusta su naturaleza automática. Gracias. –

3

Hay una biblioteca para permitir la implementación de la cola productor-consumidor en Delphi using condition variables. Este escenario es en realidad el ejemplo discutido.

El ejemplo clásico de condición variables es el productor/consumidor problema. Uno o más hilos llamados productores producen artículos y los agregan a una cola. Los consumidores (otros hilos) consumen elementos eliminando los artículos producidos de la cola.

Cuestiones relacionadas