ThreadPool - A simple C++11 Thread Pool implementation

ThreadPool

A simple C++11 Thread Pool implementation.

Basic usage:

// create thread pool with 4 worker threads
ThreadPool pool(4);

// enqueue and store future
auto result = pool.enqueue([](int answer) { return answer; }, 42);

// get result from future
std::cout << result.get() << std::endl;
Comments
  • condition.wait deadlock

    condition.wait deadlock

    Hello,

    Sometimes, after a worker has begun waiting, the other threads cannot lock the mutex anymore. I don't get why... This occurs very rarely, roughly once every 30000 call to enqueue(). It is however a serious issue for my use case.

    To track the issue, I have added some prints in enqueue() and the worker :

    Prints in enqueue :

    std::future<return_type> res = task->get_future();
    cout << "enqueue waiting for lock" << endl;
    {
        cout << "enqueue locked" << endl;
        std::unique_lock<std::mutex> lock(queue_mutex);
    
        // don't allow enqueueing after stopping the pool
        if(stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");
    
        tasks.emplace([task](){ (*task)(); });
        cout << "enqueue will unlock" << endl;
    }
    cout << "enqueue will notify" << endl;
    condition.notify_one();
    cout << "enqueue notified" << endl;
    

    Prints in the worker lambda :

                    std::function<void()> task;
                    cout << "worker "<<i<<" waiting for lock" <<endl;
                    {
                        std::unique_lock<std::mutex> lock(this->queue_mutex);
                        cout << "worker "<<i<<" waiting" << endl;
                        this->condition.wait(lock,
                            [this]{ return this->stop || !this->tasks.empty(); });
                        cout << "worker "<<i<<" awoken" << endl;
                        if(this->stop && this->tasks.empty())
                            return;
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    cout << "worker "<<i<<" released"<<endl;
                    task();
    

    When the deadlock happens I get :

    enqueue waiting for lock enqueue locked enqueue will unlock enqueue will notify worker 5 awoken worker 5 released worker 3 waiting for lock worker 3 waiting enqueue notified enqueue waiting for lock enqueue locked enqueue will unlock enqueue will notify worker 6 waiting for lock worker 6 waiting worker 6 awoken worker 6 released worker 4 waiting for lock worker 4 waiting worker 5 waiting for lock worker 6 waiting for lock

    Two things I don't get

    • why the main thread hangs ? (I should get a "enqueue notified")
    • why is this deadlock happening ? (condition.wait should have been called and released the lock..)

    I hope I don't give you too much of a headach Cheers

  • 100% CPU utilization

    100% CPU utilization

    Hello there,

    At first, I'd like to thank you for your great work. I just imported the code in my project and it just working fine. :)

    However, one thing that bothers me is that as soon I create the thread pool (and ofcourse adding some initial tasks in there), the CPU usage is getting increases over the time and eventually reach 100% (after 10sec), with considering the fact that there is no remaining tasks in queue.

    Is it normal behavior ? or am I doing something wrong ? and If you have suggestion for me.

    btw, my build environment is FreeBSD 10.2 amd64 RELEASE

    Thank you,

  • Deadlock spotted!

    Deadlock spotted!

    basically I was just profiling to see how many empty jobs can be scheduled every frame to get idea of average overhead.. and it happened that the queue incurs in deadlocks! The following code reproduce the error on my machine (you just need to play with number of threads in pool and initial recursive depth, the deadlock will necessarily occurs first or later.)

    In the few cases in wich following code didn't deadlocked it required ~200 ms (2x2Ghz cores) so 5000 jobs per second is actual throughput if you remove the deadlock.

    void recursiveWork(ThreadPool & pool, int depth){ if (depth<=0) return; auto result = pool.enqueue( {return 1;}); //empty job.. apparently the formatting remove some parentheses //here, I'm just passing a lambda that returns 1 by the way recursiveWork(pool, depth-1); result.get(); }

    int main(){ ThreadPool pool(4); for (int i= 0; i<1000; i++){ recursiveWork(pool,4); } return 0; }

  • using previous example code breaks

    using previous example code breaks

    using the 'usage' code from your previous blog post doesn't compile:

    #include "ThreadPool.h"
    #include <stdio.h>
    #include <iostream>
    
    int main() {
        // create a thread pool of 4 worker threads
        ThreadPool pool(4);
    
        // queue a bunch of "work items"
        for(int i = 0;i<8;++i)
        {
            pool.enqueue([i]
            {
                std::cout << "hello " << i << std::endl;
    
                std::cout << "world " << i << std::endl;
            });
        }
    }
    

    errors out with:

    main.cpp: In function 'int main()':
    main.cpp:17:7: error: no matching function for call to 'ThreadPool::enqueue(main()::<lambda()>)'
    main.cpp:17:7: note: candidate is:
    In file included from main.cpp:1:0:
    ThreadPool.h:117:15: note: template<class T, class F> Result<T> ThreadPool::enqueue(F)
    ThreadPool.h:117:15: note:   template argument deduction/substitution failed:
    main.cpp:17:7: note:   couldn't deduce template parameter 'T'
    scons: *** [build/main.o] Error 1
    
  • How to pass multi parameters to pool.enqueue?

    How to pass multi parameters to pool.enqueue?

    Hello, I looked example.cpp and found that the example pass i to pool.enqueue. But in fact, I would like to use this pool to run a function with multi parameters. The code seems a little confusing to me, so l'd like to ask how to pass multi parameters to pool.enqueue?

  • perfect thread pool

    perfect thread pool

    if one thread cost many many time , other thread would be blocked. all thread can not execute on same time .

    threadpool.h should be modified. insert "lock.unlock()" before line 55.

    bye the way, i have a question. why do you add lock in the line 99 when destroy threadpool? because this lock. application can not exit when destroy threadpool.

  • avoid pending when stop worker thread

    avoid pending when stop worker thread

    Under given conditions, worker thread may be suspended

    The main thread destruct pool instance:

        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
    

    In worker thread, insert a statement to sleep make the problem happen:

          std::function<void()> task;
    
           {
                    // sleep 1 second, let main thread destruct pool first
                    std::this_thread::sleep_for(std::chrono::seconds(1));
    
                    std::unique_lock<std::mutex> lock(this->queue_mutex);
    
                    // WILL WAIT FOREVER!!!
                    this->condition.wait(lock,
                                [this]{ return this->stop || !this->tasks.empty(); });
    
    
  • Race Condition in ThreadPool Destructor

    Race Condition in ThreadPool Destructor

    There's a race condition for the shared resource stop in the ThreadPool destructor. Change the definition of lock to be as follows:

    std::lock_guard<std::mutex> lock(this->queue_mutex);
    
  • Make Failed when include ThreadPool.h

    Make Failed when include ThreadPool.h

    make: Warning: File `Makefile' has modification time 708 s in the future g++ -std=c++11 -g -Dmacro -c -o main.o main.cpp In file included from main.cpp:15:0: ThreadPool.h:19:57: error: macro "F" requires 3 arguments, but only 1 given -> std::future<typename std::result_of<F(Args...)>::type>; ^ ThreadPool.h:64:53: error: macro "F" requires 3 arguments, but only 1 given -> std::future<typename std::result_of<F(Args...)>::type> ^ ThreadPool.h:66:58: error: macro "F" requires 3 arguments, but only 1 given using return_type = typename std::result_of<F(Args...)>::type;

  • threadpool for member function

    threadpool for member function

    hi I wonder how can i use the threadpool for member funtion in class and my code like:

    UAVProcessThreadPool threadPool(2); std::vector<std::future> errReturn; for(const auto iter:feature) { errReturn.emplace_back(threadPool.UAVProcess_Enterqueue( [](FeatureParam param){UAVProcessFeatExtractEach(param);} ,&iter.second )); }

    the code is in member funtion and function UAVProcessFeatExtractEach is also a member funtion, could you please show me a sample of how to use the threadpool in condition like this?

  • What will be the appropriate value for a pool size?

    What will be the appropriate value for a pool size?

    Hi,

    Can any one suggest me how to select an appropriate pool_size value ?

    ThreadPool pool(pool_size);
    

    WIll it be equivalent to number of CPU cores on the system ? Or can be greater than it too ?

    How do you select it? Specifically if code is supposed to run on different systems?

  • A simple problem about enqueue()

    A simple problem about enqueue()

    How can i do this?

    class A
    {
    public:
        void a(){
            ThreadPool pool(4);
            pool.enqueue(b);
        }
    private:
        void b(){
            num++;
        }
        int num;
    }
    

    What i see is :No instance of function template 'ThreadPool::enqueue' matching argument list.

  • Support for dynamic running threads

    Support for dynamic running threads

    The threads count is fixed after initialization.

    For example, if the thread count is 4 and the first 4 threads all need much time to finish.

    Now, the fifth thread will wait long time to get any CPU time slice.

  • Compiles normally on Linux but generates core files when running

    Compiles normally on Linux but generates core files when running

    I have tried compiling and running this program on a Windows system and it worked fine. When I try to compile and run on a Linux system, it compiles fine, but the core file appears when I run it.

    After analysis, I think the problem is in the emplace_back() function. In the Windows environment, the emplace_back() function refers to the _M_realloc_insert() function; but in the Linux environment, the same location is replaced by the _M_emplace_back_aux() function.

    I'm new to programming and don't understand why such a difference would cause the software to fail, and I'm hoping for an answer. If I want to run this program in Linux environment, how can I modify the main function?

  • Problem with passing std::unique_ptr

    Problem with passing std::unique_ptr

    #include "ThreadPool.h"
    #include <stdio.h>
    
    class Foo {
    public:
        Foo();
        void Process(std::unique_ptr<uint16_t[]> im);
    private:
        void ProcessImpl(std::unique_ptr<uint16_t[]> im);
        ThreadPool t;
    };
    
    Foo::Foo() : t(4) {
    }
    
    void Foo::Process(std::unique_ptr<uint16_t[]> im) {
    #if 0
        ProcessImpl(std::move(im));
    #else
        t.enqueue(&Foo::ProcessImpl, this, std::move(im));
    #endif
    }
    
    void Foo::ProcessImpl(std::unique_ptr<uint16_t[]> im) {
        printf("%p\n", im.get());
    }
    
    int main()
    {
        Foo f;
        auto p = std::make_unique<uint16_t[]>(100);
        printf("%p\n", p.get());
    
        f.Process(std::move(p));
    }
    

    This doesn't compile.

Thread pool - Thread pool using std::* primitives from C++17, with optional priority queue/greenthreading for POSIX.

thread_pool Thread pool using std::* primitives from C++11. Also includes a class for a priority thread pool. Requires concepts and C++17, including c

Sep 23, 2022
Thread-pool-cpp - High performance C++11 thread pool

thread-pool-cpp It is highly scalable and fast. It is header only. No external dependencies, only standard library needed. It implements both work-ste

Sep 9, 2022
EOSP ThreadPool is a header-only templated thread pool writtent in c++17.

EOSP Threadpool Description EOSP ThreadPool is a header-only templated thread pool writtent in c++17. It is designed to be easy to use while being abl

Apr 22, 2022
ThreadPool - A fastest, exception-safety and pure C++17 thread pool.

Warnings Since commit 468129863ec65c0b4ede02e8581bea682351a6d2, I move ThreadPool to C++17. (To use std::apply.) In addition, the rule of passing para

Sep 9, 2022
ThreadPool - Lightweight, Generic, Pure C++11 ThreadPool

ThreadPool Lightweight, Generic, Pure C++11 ThreadPool Rational I needed a Thread Pool for something I was writing, and I didn't see any that I liked.

Aug 17, 2022
An ultra-simple thread pool implementation for running void() functions in multiple worker threads
An ultra-simple thread pool implementation for running void() functions in multiple worker threads

void_thread_pool.cpp © 2021 Dr Sebastien Sikora. seb.nf.[email protected] Updated 06/11/2021. What is it? void_thread_pool.cpp is an ultra-simple

Nov 19, 2021
A modern thread pool implementation based on C++20
A modern thread pool implementation based on C++20

thread-pool A simple, functional thread pool implementation using pure C++20. Features Built entirely with C++20 Enqueue tasks with or without trackin

Oct 2, 2022
Pool is C++17 memory pool template with different implementations(algorithms)

Object Pool Description Pool is C++17 object(memory) pool template with different implementations(algorithms) The classic object pool pattern is a sof

Sep 27, 2022
A easy to use multithreading thread pool library for C. It is a handy stream like job scheduler with an automatic garbage collector. This is a multithreaded job scheduler for non I/O bound computation.

A easy to use multithreading thread pool library for C. It is a handy stream-like job scheduler with an automatic garbage collector for non I/O bound computation.

Jun 4, 2022
A C++17 thread pool for high-performance scientific computing.

We present a modern C++17-compatible thread pool implementation, built from scratch with high-performance scientific computing in mind. The thread pool is implemented as a single lightweight and self-contained class, and does not have any dependencies other than the C++17 standard library, thus allowing a great degree of portability

Oct 3, 2022
An easy to use C++ Thread Pool

mvThreadPool (This library is available under a free and permissive license) mvThreadPool is a simple to use header only C++ threadpool based on work

Sep 24, 2022
High Performance Linux C++ Network Programming Framework based on IO Multiplexing and Thread Pool

Kingpin is a C++ network programming framework based on TCP/IP + epoll + pthread, aims to implement a library for the high concurrent servers and clie

Sep 30, 2022
Work Stealing Thread Pool

wstpool Work Stealing Thread Pool, Header Only, C++ Threads Consistent with the C++ async/future programming model. Drop-in replacement for 'async' fo

Aug 13, 2022
MAN - Man is Thread Pool in C++17

Introduction MAN is a ThreadPool wrote in C++17. The name is chosen because, at least in France, it is said that men are not able to do several things

Mar 6, 2022
CTPL - Modern and efficient C++ Thread Pool Library

CTPL Modern and efficient C++ Thread Pool Library A thread pool is a programming pattern for parallel execution of jobs, http://en.wikipedia.org/wiki/

Sep 30, 2022
DwThreadPool - A simple, header-only, dependency-free, C++ 11 based ThreadPool library.
DwThreadPool - A simple, header-only, dependency-free, C++ 11 based ThreadPool library.

dwThreadPool A simple, header-only, dependency-free, C++ 11 based ThreadPool library. Features C++ 11 Minimal Source Code Header-only No external depe

May 29, 2022
Smart queue that executes tasks in threadpool-like manner

execq execq is kind of task-based approach of processing data using threadpool idea with extended features. It supports different task sources and mai

Aug 11, 2022
Light, fast, threadpool for C++20

riften::Thiefpool A blazing-fast, lightweight, work-stealing thread-pool for C++20. Built on the lock-free concurrent riften::Deque. Usage #include "r

Sep 23, 2022
Threadpool c++17 - 采用多线程多对列,每个线程控制一个队列,替代老的多个线程公用一个队列

ThreadPool c++17 采用多线程多对列,每个线程控制一个队列,替代老的多个线程公用一个队列。 将任务拆分多个下发给每个线程,每个线程掌管 M(tasks) / N(threads)个任务 M(tasks) / N(threads)个任务 公用一个队列。减少竞争。 使用方法: 初始化线程池

Apr 25, 2022