Skip to main content
added 724 characters in body; edited tags; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

A custom thread-pool/queue class.

I wanted a class which executes any number of tasks but only a certain amount at the same time (e.g. to download various internet content and keep the overall download speed at a good level). The class iI wrote seems to work but there are probably things that can be improved. e.g.

  1. Do thosethese locks make sense? Should there be other locks as well?
  2. I have a method and an event that is only relevant if a specific constructor is used, is. Is there a way to improve that?
  3. The class iI use for tasks is ThreadStart, is. Is that a good idea?
  4. There might be better method names/class names.
  5. Are there any general errors e(e.g. that more Threads than the max-count will be executed)?

There are probably more points that could be improved. Also, also if anyone knows a good open source library (or native .NET class even) which does just what my class is supposed to do i, I would be interested in that too.

Here be code:

public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execution of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }
 
}

A custom thread-pool/queue class.

I wanted a class which executes any number of tasks but only a certain amount at the same time (e.g. to download various internet content and keep the overall download speed at a good level). The class i wrote seems to work but there are probably things that can be improved. e.g.

  1. Do those locks make sense? Should there be other locks as well?
  2. I have a method and an event that is only relevant if a specific constructor is used, is there a way to improve that?
  3. The class i use for tasks is ThreadStart, is that a good idea?
  4. There might be better method names/class names
  5. Are there any general errors e.g. that more Threads than the max-count will be executed?

There are probably more points that could be improved, also if anyone knows a good open source library (or native .NET class even) which does just what my class is supposed to do i would be interested in that too.

Here be code:

public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execution of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }
 
}

A custom thread-pool/queue class

I wanted a class which executes any number of tasks but only a certain amount at the same time (e.g. to download various internet content and keep the overall download speed at a good level). The class I wrote seems to work but there are probably things that can be improved.

  1. Do these locks make sense? Should there be other locks as well?
  2. I have a method and an event that is only relevant if a specific constructor is used. Is there a way to improve that?
  3. The class I use for tasks is ThreadStart. Is that a good idea?
  4. There might be better method names/class names.
  5. Are there any general errors (e.g. that more Threads than the max-count will be executed)?

There are probably more points that could be improved. Also, if anyone knows a good open source library (or native .NET class even) which does just what my class is supposed to do, I would be interested in that too.

public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execution of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }
}
Tweeted twitter.com/#!/StackCodeReview/status/36528108911869952
deleted 1 characters in body
Source Link
brunnerh
  • 335
  • 1
  • 2
  • 9
public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execturionexecution of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }

}
public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execturion of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }

}
public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execution of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }

}
Source Link
brunnerh
  • 335
  • 1
  • 2
  • 9

A custom thread-pool/queue class.

I wanted a class which executes any number of tasks but only a certain amount at the same time (e.g. to download various internet content and keep the overall download speed at a good level). The class i wrote seems to work but there are probably things that can be improved. e.g.

  1. Do those locks make sense? Should there be other locks as well?
  2. I have a method and an event that is only relevant if a specific constructor is used, is there a way to improve that?
  3. The class i use for tasks is ThreadStart, is that a good idea?
  4. There might be better method names/class names
  5. Are there any general errors e.g. that more Threads than the max-count will be executed?

There are probably more points that could be improved, also if anyone knows a good open source library (or native .NET class even) which does just what my class is supposed to do i would be interested in that too.

Here be code:

public class ThreadQueue
{
    private readonly HashSet<ThreadStart> WorkingThreads = new HashSet<ThreadStart>();
    private readonly Queue<ThreadStart> Queue = new Queue<ThreadStart>();

    private bool RaiseCompleteEventIfQueueEmpty = false;

    private int ThreadsMaxCount;

    public ThreadQueue(int threadsMaxCount)
    {
        ThreadsMaxCount = threadsMaxCount;
    }

    /// <summary>
    /// Creates a new thread queue with a maximum number of threads and the tasks that should be executed.
    /// </summary>
    /// <param name="threadsMaxCount">The maximum number of currently active threads.</param>
    /// <param name="tasks">The tasks that should be executed by the queue.</param>
    public ThreadQueue(int threadsMaxCount, ThreadStart[] tasks) : this(threadsMaxCount)
    {
        RaiseCompleteEventIfQueueEmpty = true;
        foreach (ThreadStart task in tasks)
        {
            Queue.Enqueue(task);
        }
    }

    /// <summary>
    /// Starts to execute tasks. Used in conjunction with the constructor in which all tasks are provided.
    /// </summary>
    public void Start()
    {
        CheckQueue();
    }

    private readonly object addlock = new object();
    /// <summary>
    /// Adds a task and runs it if a execution slot is free. Otherwise it will be enqueued.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    public void AddTask(ThreadStart task)
    {
        lock (addlock)
        {
            if (WorkingThreads.Count == ThreadsMaxCount)
            {
                Queue.Enqueue(task);
            }
            else
            {
                StartThread(task);
            }
        }
    }

    /// <summary>
    /// Starts the execturion of a task.
    /// </summary>
    /// <param name="task">The task that should be executed.</param>
    private void StartThread(ThreadStart task)
    {
        WorkingThreads.Add(task);
        BackgroundWorker thread = new BackgroundWorker();
        thread.DoWork += delegate { task.Invoke(); };
        thread.RunWorkerCompleted += delegate { ThreadCompleted(task); };
        thread.RunWorkerAsync();
    }

    private void ThreadCompleted(ThreadStart start)
    {
        WorkingThreads.Remove(start);
        CheckQueue();
        if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
    }

    private readonly object checklock = new object();
    /// <summary>
    /// Checks if the queue contains tasks and runs as many as there are free execution slots.
    /// </summary>
    private void CheckQueue()
    {
        lock (checklock)
        {
            while (Queue.Count > 0 && WorkingThreads.Count < ThreadsMaxCount)
            {
                StartThread(Queue.Dequeue());
            }
            if (Queue.Count == 0 && WorkingThreads.Count == 0 && RaiseCompleteEventIfQueueEmpty) OnCompleted();
        }
    }

    /// <summary>
    /// Raised when all tasks have been completed. Will only be used if the ThreadQueue has been initialized with all the tasks it should execute.
    /// </summary>
    public event EventHandler Completed;

    /// <summary>
    /// Raises the Completed event.
    /// </summary>
    protected void OnCompleted()
    {
        if (Completed != null)
        {
            Completed(this, null);
        }
    }

}