2015-11-27 10 views
6

Varie risposte suggeriscono che è una cattiva idea dormire in una discussione, ad esempio: Avoid sleep. Perché esattamente? Una ragione spesso data è che è difficile uscire con grazia dal thread (segnalandolo per terminarlo) se sta dormendo.Alternativa per dormire all'interno di una discussione

Diciamo che volevo controllare periodicamente i nuovi file in una cartella di rete, forse una volta ogni 10 secondi. Questo sembra perfetto per un thread con la priorità impostata su basso (o più basso) perché non voglio che l'I/O del file potenzialmente dispendioso possa influire sul thread principale.

Quali sono le alternative? Codice è fornito in Delphi, ma si applica anche a qualsiasi applicazione multi-threaded:

procedure TNetFilesThrd.Execute(); 
begin 
    try 
     while (not Terminated) do 
      begin 
      // Check for new files 
      // ... 

      // Rest a little before spinning around again 
      if (not Terminated) then 
       Sleep(TenSeconds); 
      end; 
    finally 
     // Terminated (or exception) so free all resources... 
    end; 
end; 

Una modifica minore può essere:

// Rest a little before spinning around again 
nSleepCounter := 0; 
while (not Terminated) and (nSleepCounter < 500) do 
    begin 
    Sleep(TwentyMilliseconds); 
    Inc(nSleepCounter); 
    end; 

ma ciò comporta ancora un sonno ...

+1

Dormire in un thread può anche essere pericoloso e causare un comportamento indefinito quando si utilizza il multithreading. – ITguy

+1

L'alternativa migliore è aspettare un evento di segnale per lo stesso timeout; se l'evento è segnalato, si esce immediatamente dal thread, se si ha il timeout si rimane nel ciclo 'while'. – kludg

+9

@ITguy Il sonno non ha pericoli intrinseci e non porta a comportamento non definito –

risposta

8

L' modo standard per farlo è aspettare un evento di cancellazione. In pseudo-codice che assomiglia a questo:

while not Terminated do 
begin 
    // Check for new files 
    // ... 

    // Rest a little before spinning around again 
    FTerminationEvent.WaitFor(TenSeconds); 
end; 

Per terminare si sarebbe ignorare TerminatedSet:

procedure TMyThread.TerminatedSet; 
begin 
    inherited; 
    FTerminationEvent.SetEvent; // abandon the wait in the thread method 
end; 

L'attesa per l'evento sia in timeout, o termina perché l'evento viene segnalato. Ciò consente al thread di sospendere per un po 'e non sovraccaricare la CPU, e tuttavia anche di rispondere alle richieste di terminazione.

+0

Sai cosa è l'unità Delphi-7 (o equivalente D7) per FTerminationEvent? Sono occupato con Google per cercare di trovarlo ma correndo giù per le buchette di coniglio al momento! ... – AlainD

+1

@AlainD hai bisogno di standart TEvent, FTerminationEvent è solo un nome variabile per capire cosa significa questo evento. –

+0

@YuriyAfanasenkov: Aah, ok grazie! Ho trovato questo articolo (http://stackoverflow.com/questions/1734644/how-to-start-stop-a-monitoring-delphi-thread-on-demand) e lo sto seguendo ora. Verificherà e farà rapporto a breve. – AlainD

1

Se questo era il mio lavoro, penso che avrei risolto con una classe wrapper con un TTimer in esso, generando un nuovo thread ogni 10 secondi.

Generare un nuovo thread è un po 'costoso, ma se si tratta di qualcosa che si esegue solo ogni 10 secondi, la performance colpita sul thread principale è trascurabile, penso.

Passi:

  1. Creare una classe wrapper, TMyFileSearcher.
  2. Lascia che contenga un TTimer.
  3. Ogni volta che il timer tocca, genera un nuovo thread e cerca i file.
  4. Aggiungere un gestore OnTerminate a TMyFileSearcher per elaborare i file restituiti.

Ci sarebbero anche altre considerazioni, come tenere traccia di se un thread è stato generato, in modo da non creare un nuovo thread mentre quello vecchio è in esecuzione.

Ma, a parte questo, penso che dovrebbe essere abbastanza semplice da implementare.