Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to sleep inside a thread

Various answers suggest it is a bad idea to sleep inside a thread, for example: Avoid sleep. Why exactly? One reason often given is that it is difficult to gracefully exit the thread (by signalling it to terminate) if it is sleeping.

Let's say I wanted to periodically check for new files in a network folder, maybe once every 10s. This seems perfect for a thread with the priority set to low (or lowest) because I don't want the potentially time-consuming file I/O to impact my main thread.

What are the alternatives? Code is given in Delphi but would apply equally to any multi-threaded application:

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;

A minor modification might be:

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

but this still involves a Sleep...

like image 709
AlainD Avatar asked Nov 27 '15 15:11

AlainD


2 Answers

The standard way to do this is to wait on a cancellation event. In pseudo code that looks like this:

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

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

In order to terminate you would override TerminatedSet:

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

The wait on the event either times out, or terminates because the event is signaled. This allows your thread to pause for a while and not burden the CPU, and yet also remain responsive to requests to terminate.

like image 59
David Heffernan Avatar answered Sep 27 '22 17:09

David Heffernan


If this was my job, I think I would have solved it with a wrapper class with a TTimer in it, spawning a new thread every 10 seconds.

Spawning a new thread is somewhat costly, but if it's something that you do only every 10 seconds, the performance hit to the main thread is negligible, I think.

Steps:

  1. Create a wrapper class, TMyFileSearcher.
  2. Let it contain a TTimer.
  3. Each time the timer hits, spawn a new thread and search for the files.
  4. Add an OnTerminate handler to TMyFileSearcher, to process the returned files.

There'd be some other considerations too, such as keeping track of whether or not a thread has been spawned, so that you do not create an new thread while the old one is running.

But, other than this, I think it should be pretty straight forward to implement.

like image 23
bjaastad_e Avatar answered Sep 27 '22 16:09

bjaastad_e