user3021830
user3021830

Reputation: 2924

Writing a custom ThreadPool

I am trying to write a Custom Thread Pool object to run a certain function that might take long time.

I have written the following to code to run a simulation:

namespace TPConsoleTest
{
    class Program
    {
        private static MyThreadPool tp = null;

        static void Main(string[] args)
        {
            // Create new thread pool
            tp = new MyThreadPool(5);
            // Register on completion event
            tp.OnThreadDone += tp_OnThreadDone;

            for (int i = 0; i < 20; i++)
            {
                tp.AddThread(i);
            }
            // Wait for exit
            Console.ReadKey();
        }

        static void tp_OnThreadDone(string name, int ix)
        {
            // Remove finished thread from pool
            tp.RemoveThread(name);
            // Write messsage
            Console.WriteLine("Thread {0} ended for : #{1}", name, ix);
        }
    }
}

namespace TPConsoleTest
{
    class MyThreadPool
    {
        private IList<Thread> _threads;
        private int _maxThreads = 0;

        public bool IsPoolAvailable
        {
            get
            {
                if (this._threads != null && this._threads.Count(x => x.IsAlive) < this._maxThreads)
                    return true;
                else
                    return false;
            }
        }
        public delegate void ThreadDone(string name, int id);
        public event ThreadDone OnThreadDone;

        public MyThreadPool(int maxThreadCount)
        {
            // Set maximum number of threads
            this._maxThreads = maxThreadCount;
            // Initialize pool
            this._threads = new List<Thread>();
        }
        public void AddThread(int ix)
        {
            // If maximum number is reached, wait for an empty slot
            while (!this.IsPoolAvailable)
            {
                Thread.Sleep(100);
            }
            // Create a unique name for the threae
            string tName = Guid.NewGuid().ToString();
            Thread t = new Thread(() =>
                {
                    // Do this time-consuming operation
                    MyWorker w = new MyWorker();
                    w.DoWork(tName, ix);
                });
            t.IsBackground = true;
            t.Name = tName;
            t.Start();
            // Add to pool
            this._threads.Add(t);

            // Fire event when done
            if (OnThreadDone != null)
                OnThreadDone(t.Name, ix);
        }
        public void RemoveThread(string name)
        {
            // Find event from name and remove it from the pool to allocate empty slot
            Thread t = this._threads.FirstOrDefault(x => x.Name == name);
            if (t != null)
                this._threads.Remove(t);
        }
    }
}


namespace TPConsoleTest
{
    public class MyWorker
    {
        public void DoWork(string threadName, int ix)
        {
            // Dispatch a message signalling process start
            Console.WriteLine("Thread {0} started for : #{1}", threadName, ix);
            Random rnd = new Random();
            int delay = rnd.Next(5);
            delay++;
            // Wait up to 5 second for each process. It may shorter or longer depending to a random value
            Thread.Sleep(delay * 1000);
        }
    }
}

And I get the following results: enter image description here

The problems are :

  1. The command to simulate process delay Thread.Sleep(delay * 1000); does not seem to work. Everything happens in lightning speed.
  2. As you can see from the messages, some thread results are received before the thread has even started.

How can I fix these errors?

Upvotes: 0

Views: 552

Answers (1)

Jcl
Jcl

Reputation: 28272

You are calling OnThreadDone immediately after creating the thread, without waiting for it to complete:

t.Start();    
this._threads.Add(t);

// The event is fired without waiting for the thread to end
if (OnThreadDone != null)
   OnThreadDone(t.Name, ix);

You are supposed to call it when the worker method on your thread ends, not right after starting the thread

Upvotes: 2

Related Questions