// Add work to be execute on the thread pool
    public void AddWork(Action <ThreadContainer> workFunction, WorkFinished onWorkFinished)
    {
        // Create struct for passing args into ThreadFunction
        ThreadFunctionArgs args = new ThreadFunctionArgs
        {
            work      = workFunction,
            container = new ThreadContainer
            {
                OnWorkFinished = onWorkFinished,
            },
        };

        // Queue work item on ThreadPool
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadFunction), args);

        // Add container to set of currently running containers
        threadContainers.Add(args.container);
    }
    // Function invoked be every thread
    static void ThreadFunction(object inputObject)
    {
        // Get actual arguments from Object parameter
        ThreadFunctionArgs args = (ThreadFunctionArgs)inputObject;

        try
        {
            // Call work function with container reference
            args.work(args.container);

            // Mark thread as finished
            args.container.HasFinished = true;
        }
        catch (Exception e)
        {
            args.container.HasError = true;
            args.container.Error    = e;
        }
    }