As an exercise in using C++11 features I decided to make a thread pool class.I would like to have a review on the code with focus on:Standards compliance / Portability issues / Best practicesThread Safety / Exception handlingAPIPerformance issues (Yes I know std::mutex is slow on windows, but besides that :)Any ideas on how I can get rid of the specialization on void return type?I have inlined all methods in the class declaration to make it easier to read here. In the actual implementation they are not inlined. Sorry for the failed line-breaks on some places, the CR code window is a bit narrower than I'd like.#include <functional>#include <future>#include <deque>#include <thread>/// <summary> A typical thread worker queue that can execute arbitrary jobs. /// </summary>////// <remarks>///  * Thread Safety   : Full.///  * Exception Safety: Strong. </remarks>class WorkQueue{public:    /// <summary> Constructors a new work queue object. </summary>    /// <param name=numWorkers> (Optional) number of workers, less than 0 to     ///     auto-detect (may fail on esoteric platforms). </param>    explicit WorkQueue(int numWorkers = -1){        if (numWorkers < 1){            numWorkers = std::thread::hardware_concurrency() + 1;        }        while (numWorkers--){            m_workers.emplace_back(std::thread(&WorkQueue::doWork, this));        }    }    /// <summary> Will abort all pending jobs and run any in-progress jobs to     ///     completion upon destruction. </summary>    ~WorkQueue(){        abort();    }    /// <summary> Stops work queue and finishes jobs currently being executed.    ///     Queued jobs that have not begun execution will have their promises     ///     broken. </summary>    void abort(){        m_exit = true;        m_finish_work = false;        m_signal.notify_all();        joinAll();        {            std::lock_guard<std::mutex> lg(m_mutex);            m_work.clear();        }    }    /// <summary> Stops new work from being submitted to this work queue.</summary>    void stop(){        m_exit = true;        m_finish_work = true;        m_signal.notify_all();    }    /// <summary> Wait for completion of all submitted work. No more work will     ///     be allowed to be submitted. </summary>    void waitForCompletion(){        stop();        joinAll();        assert(m_work.empty());    }    /// <summary> Executes the given function asynchronously. </summary>    /// <exception cref=std::runtime_error> Thrown if attempting to submit a job    ///     to a work queue that is terminating. </exception>    /// <param name=function> [in] The function to execute. </param>    /// <returns> A std::future<RETVAL> for the result that will be generated by     ///     the function argument. Exceptions from the function will be     ///     thrown by get() on the future.</returns>    template<typename RETVAL>    std::future<RETVAL> submit(std::function<RETVAL()>&& function){        if (m_exit){            throw std::runtime_error(Caught work submission to work queue that is desisting.);        }        // Workaround for lack of lambda move capture        typedef std::pair<std::promise<RETVAL>, std::function<RETVAL()>> pair_t;        std::shared_ptr<pair_t> data = std::make_shared<pair_t>(std::promise<RETVAL>(), std::move(function));        std::future<RETVAL> future = data->first.get_future();        {            std::lock_guard<std::mutex> lg(m_mutex);            m_work.emplace_back([data](){                try{                    data->first.set_value(data->second());                }                catch (...){                    data->first.set_exception(std::current_exception());                }            });        }        m_signal.notify_one();        return std::move(future);    }    template<>    std::future<void> submit(std::function<void()>&& function){        if (m_exit){            throw std::runtime_error(Caught work submission to work queue that is desisting.);        }        // Workaround for lack of lambda move capture        typedef std::pair<std::promise<void>, std::function<void()>> pair_t;        std::shared_ptr<pair_t> data = std::make_shared<pair_t>(std::promise<void>(), std::move(function));        std::future<void> future = data->first.get_future();        {            std::lock_guard<std::mutex> lg(m_mutex);            m_work.emplace_back([data](){                try{                    data->second();                    data->first.set_value();                }                catch (...){                    data->first.set_exception(std::current_exception());                }            });        }        m_signal.notify_one();        return std::move(future);    }private:    std::deque<std::function<void()>> m_work;    std::mutex m_mutex;    std::condition_variable m_signal;    std::atomic<bool> m_exit{ false };    std::atomic<bool> m_finish_work{ true };    std::vector<std::thread> m_workers;    void doWork(){        std::unique_lock<std::mutex> ul(m_mutex);        while (!m_exit || (m_finish_work && !m_work.empty())){            if (!m_work.empty()){                std::function<void()> work(std::move(m_work.front()));                m_work.pop_front();                ul.unlock();                work();                ul.lock();            }            else{                m_signal.wait(ul);            }        }    }    void joinAll(){        for (auto& thread : m_workers){            thread.join();        }        m_workers.clear();    }    void operator=(const WorkQueue&) = delete;    WorkQueue(const WorkQueue&) = delete;};Example use:int main(){    WorkQueue wq;    wq.submit<void>([](){std::cout << foo << std::endl; });    wq.submit<void>([](){std::cout << bar << std::endl; });    std::future<int> f0 = wq.submit<int>([](){return 4; });    std::future<int> f1 = wq.submit<int>([](){return 40; });    std::cout << f1.get() << std::endl;    wq.waitForCompletion();    std::cout << f.get() << std::endl;    return 0;}
Thread pool worker implementation
c++;c++11;thread safety;reinventing the wheel
Please note that the code should be presented in the same way that you use it to avoid spurious errors. Compiling your code as is, gave me an error on the specialization of submit.Namingpair_t is a rather generic name that does not tell what is storedm_work could be improved a little although I don't have any idea yetm_mutex should be renamed to m_work_mutex to indicate what it is for (or bundle it together with m_work to make it impossible to access m_work without locking m_mutex)m_signal could take at least some explanation about its uses: what does it signal? Maybe the name can reflect this as well.m_exit should be named something like m_accept_no_more_work (or accept_more_work and its logic should be inverted because negation in a (boolean) variable name makes reasoning harder)m_workers could be name m_worker_threadsDerive the return type automaticallyWhy bother the user with giving the return type to submit when it can be extracted?template <typename FunctionObject>auto submit(FunctionObject &&function) -> std::future<decltype(function())>;Remove code duplication in submitYour two submit functions have largely the same code which indicates that your switch on the template parameter is too coarse. The only differing part is in the try{} block. The obvious solution is to extract the differing parts into an own function. For shortness I will use a template function specialization:template <>inline void WorkQueue::execute_and_set_data<void>(const DataPointer<void> &data) {    data->second();    data->first.set_value();}template <typename ReturnType>void WorkQueue::execute_and_set_data(const DataPointer<ReturnType> &data) {    data->first.set_value(data->second());}These functions use some template types:template <typename ReturnType>using PromiseFunctionPair =    std::pair<std::promise<ReturnType>, std::function<ReturnType()>>;template <typename ReturnType>using DataPointer = std::shared_ptr<PromiseFunctionPair<ReturnType>>;And they replace the call in the try catch block. Because of the nontrivial dependency between ReturnType and these types they cannot be used for automatic template parameter deduction:try {    execute_and_set_data<ReturnType>(data);}However, I would recommend to replace PromiseFunctionPair by a templated struct with better names for the members than first and second which would then allow automatic template parameter deduction.Missing includesyou are using std::vector without #include <vector>you are using assert without #include <cassert>Typof.get() should probably be f0.get()?Besides the mentioned flaws I really enjoyed reading your code :)