0

I have class which implements an endless worker thread like this example, in my case representing a body. During runtime I will have between 0 and ~8 instances live at any time with instances constantly being created and destroyed.

Most of the time this class has a lifecycle of 30 seconds to 5 minutes but occasionally there may be a number of instances created and destroyed in a relatively short period of time. This is where I tend to run into performance issues given the low spec hardware this code is running on.

I would now like to rewrite the behavior so that I use a ThreadPool for my collection of running workers and I am struggling to find the correct way to structure the code.

Basically the code I have at the moment is something like

public class BodyCollection : IReadOnlyDictionary<ulong, TrackedBody>
{
    public void Update() 
    {
        if (createNew) 
        {
           var body = new TrackedBody();
           body.BeginTracking();
           this.Add(1234, body);
        }

        if (remove) 
        {
            TrackedBody body = this[1234];
            body.StopTracking();
            this.Remove(body);
        }
    }
}

public class TrackedBody
{
    private readonly Thread _BiometricsThread;
    private volatile bool _Continue = true;

    public TrackedBody() 
    {
        _BiometricsThread = new Thread(RunBiometricsThread);
    }

    public void BeginTracking()
    {
        _BiometricsThread.Start();
    }

    public void StopTracking() 
    {    
        _Continue = false;
    }

    private void RunBiometricsThread()
    {
        while(_Continue) 
        {
            System.Threading.Thread.Sleep(1000);
        }
    }
}

So how do I re-write the above to utilize a ThreadPool correctly and so that I can cancel running threads on the ThreadPool as required? Do I use CancellationTokens or ManualResetEvents to control the threads?

Community
  • 1
  • 1
Maxim Gershkovich
  • 45,951
  • 44
  • 147
  • 243
  • 1
    You just don't, threads like these are poison to the thread pool. They prevent other tp threads from being serviced in a timely manner. A reasonable maximum is half a second, beyond that it starts clogging the pipes pretty badly. Don't do it. – Hans Passant Sep 02 '15 at 11:02
  • @HansPassant I see... Would you say that the above holds true if even your application is the ONLY application running on the given device? – Maxim Gershkovich Sep 02 '15 at 11:06
  • This doesn't have anything to do with applications, it is about threads. – Hans Passant Sep 02 '15 at 11:18

1 Answers1

1

I strongly believe you should be using more modern methods of asynchronous programming. We are going to use the Task Parallel Library here because it gives you the features you want for free:

  • Tracking completion
  • Cancellation
  • Thread pool

public class TrackedBody
{     
    public Task BeginTrackingAsync(CancellationToken cancellation)
    {
        return Task.Run(() => RunBiometricsThread(cancellation));
    }

    private void RunBiometricsThread(CancellationToken cancellation)
    {
        while(!cancellation.IsCancellationRequested) 
        {
            Task.Delay(1000, cancellation);
        }
    }
}

Note that I have removed the async keyword. This was doing nothing on its own.

You can use the task to track the state of the ongoing work. You can use the cancellation token to stop all work.

Gusdor
  • 14,001
  • 2
  • 52
  • 64
  • The async keyword was just a typo. I am aware it was doing nothing on its own but as for the rest of your example, that could work, I will have a play with such an approach and be curious of the performance of creating multiple tasks. I would assume it should be faster than threads. I could have sworn I had tried something similar at some point but it didnt work in my context (and hence why I went back to traditional threads) but will look again with a fresh face. Thanks for your input much appreciated – Maxim Gershkovich Sep 02 '15 at 11:14
  • @MaximGershkovich The advantage of the threadpool is that the relatively expensive operation of creating and registering threads has already been done. There are no other advantages and some intersting disadvantages - oversubscription, and fragility of thread-local storage. – Gusdor Sep 02 '15 at 12:24