2015-11-27 18 views
6

Różne odpowiedzi sugerują, że spanie wewnątrz wątku to zły pomysł, na przykład: Avoid sleep. Dlaczego dokładnie? Często podawanym powodem jest to, że trudno jest z wdziękiem wyjść z wątku (sygnalizując mu zakończenie), jeśli śpi.Alternatywa do spania wewnątrz wątku

Załóżmy, że chcę okresowo sprawdzać, czy nie ma nowych plików w folderze sieciowym, może raz na 10 sekund. Wydaje się to idealne dla wątku z priorytetem ustawionym na niski (lub najniższy), ponieważ nie chcę, aby potencjalnie czasochłonne operacje we/wy pliku wpływały na mój główny wątek.

Jakie są alternatywy? Kod podany jest w Delphi ale mają również zastosowanie do każdej wielowątkowych aplikacji:

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; 

Drobna modyfikacja może być:

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

ale to nadal wiąże się z uśpienia ...

+1

Spanie w jednym wątku może również być niebezpieczne i prowadzić do nieokreślonego zachowania podczas używania wielowątkowości. – ITguy

+1

Lepszą alternatywą jest oczekiwanie na zdarzenie sygnalizacyjne dla tego samego limitu czasu; jeśli zdarzenie zostanie zasygnalizowane, natychmiast opuścisz wątek, jeśli masz czas, pozostaniesz w pętli 'while'. – kludg

+9

@ Sleeping Sleeping nie ma nieodłącznego zagrożenia i nie prowadzi do niezdefiniowanych zachowań. –

Odpowiedz

8

Standardowym sposobem na to jest czekanie na zdarzenie anulowania. W pseudo kod, który wygląda tak:

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

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

Aby zakończyć chcesz nadpisać TerminatedSet:

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

Oczekiwanie na zdarzenie albo czasami się lub kończy, ponieważ zdarzenie jest sygnalizowane. Dzięki temu wątek może zatrzymać się na chwilę i nie obciążać procesora, a jednocześnie reagować na żądania zakończenia.

+0

Czy wiesz, czym jest jednostka Delphi-7 (lub odpowiednik D7) dla FTerminationEvent? Jestem zajęty Googlingiem, aby spróbować go znaleźć, ale w tej chwili znoszę dziury w królikach! ... – AlainD

+1

@AlainD potrzebujesz standardowego TEventa, FTerminationEvent to po prostu nazwa zmiennej, aby zrozumieć, co oznacza to wydarzenie. –

+0

@YuriyAfanasenkov: Aah, ok, dzięki! Znalazłem ten artykuł (http://stackoverflow.com/questions/1734644/how-to-start-stop-a-monitoring-delphi-thread-on-demand) i podążam za nim teraz. Wypróbuje to i wkrótce się zgłoś. – AlainD

1

Jeśli to była moja praca, myślę, że rozwiązałbym ją za pomocą klasy otoki z TTimerem, tworząc nowy wątek co 10 sekund.

Tarło nowego wątku jest dość kosztowne, ale jeśli jest to coś, co robisz tylko co 10 sekund, to trafienie do głównego wątku jest nieistotne, jak sądzę.

Kroki:

  1. utworzyć klasy otoki, TMyFileSearcher.
  2. Niech zawiera TTimer.
  3. Za każdym razem, gdy licznik trafi, odradza się nowy wątek i wyszukuje pliki.
  4. Dodaj przerywnik OnTerminate do TMyFileSearcher, aby przetworzyć zwrócone pliki.

Istnieje również kilka innych czynników, takich jak śledzenie, czy wątek został utworzony, aby nie tworzyć nowego wątku, gdy działa stary.

Ale, poza tym, myślę, że powinno to być całkiem proste do wdrożenia.