ThreadPool - Lightweight, Generic, Pure C++11 ThreadPool

Overview

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. This is still somewhat a work in progress; it's stable, but there are probably places where some of the locking logic could be better. ThreadPool::JoinAll is a little sloppy, but it works.

Licensing

Public Domain. If my licensing is wrong, please let me know. Use at your own risk for whatever you want. Feel free to change the namespaces as well. Apparently licensing is hard and complicated. If your country doesn't have a public domain, feel free to say you found this on the side of the road.

Overview

ThreadPool is a super simple class that manages threads and jobs. ThreadCount threads are created at object instantiation time, and persist until the ThreadPool object is destroyed. You cannot change the thread count. A later version may allow you to set the thread count through the constructor rather than as a template parameter, but it's not something I care to do at the moment. Jobs are functions with no parameters or return values. This decision was to make it as generic as possible so it could be integrated into a variety of projects. If you can't get your job to work with those constraints, you're doing something wrong, or you need to roll your own ThreadPool. But you're probably making things overly complicated.

Below is a quick overview, but ThreadPool.h is documented, so just read that. It's less than 200 lines with comments.

template <unsigned ThreadCount = 10>
class ThreadPool {
public:
    ThreadPool();
    ~ThreadPool();
    void AddJob( std::function<void(void)> );
    unsigned Size() const;
    unsigned JobsRemaining();
    void JoinAll( bool WaitForAll = true );
    void WaitAll();
};

Examples

#include "ThreadPool.h"

#include <iostream>
#include <chrono>

int main() {
    using nbsdx::concurrent::ThreadPool;
    
    ThreadPool pool; // Defaults to 10 threads.
    int JOB_COUNT = 100;
    
    for( int i = 0; i < JOB_COUNT; ++i )
        pool.AddJob( []() { 
            std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
        } );
    
    pool.JoinAll();
    std::cout << "Expected runtime: 10 seconds." << std::endl;
}

Convience Function for running a list of jobs in a pool, assuming the type being iterated is of std::function<void(void)>:

template <typename Iter, unsigned Count = 10>
void RunInPool( Iter begin, Iter end ) {
    ThreadPool<Count> pool;
    for( ; begin != end; begin = std::next( begin ) )
        pool.AddJob( *begin );
    pool.JoinAll();
}

It's worth nothing that the pool.JoinAll(); is optional in this example, since JoinAll is invoked upon object deconstruction.

Comments
  • Reduce the unnecessary mutex

    Reduce the unnecessary mutex

    The job_available_mutex will unlock after calling the condition_variable::wait, and lock after it return. It means queue_mutex is unnecessary.

    change:

    1. reduce the unnecessary mutex
    2. avoid dead-lock in job_available_var.wait's predicate, remove the call of JobsRemaining
    opened by 1Feng 5
  • Completely rewrite ThreadPool

    Completely rewrite ThreadPool

    • Fixes deadlocks (in WaitAll and JoinAll specifically)
    • Supports setting amount of threads in constructor
    • Clearer datatypes: queue instead of list
    • Removes redundancies
    • Simplifies the code

    More info can be found here: http://stackoverflow.com/q/37110370

    opened by DomGries 2
  • Compile on VS 2012/2013

    Compile on VS 2012/2013

    atomic_bool does not have a constructor on VS 2012/2013 but can be replaced by atomic<bool> which has one. Same for atomic_int

    http://stackoverflow.com/a/15751036

    opened by DomGries 2
  • Purpose of introducing jobs_left

    Purpose of introducing jobs_left

    Hi nbsdx, I am confused about the introduction of jobs_left. What is the purpose of introducing atomic_int type jobs_left(in line 27)? I think, we could simply add the queue_mutex's lock in function WaitAll() (in line 148), rather than using the atomic_int variable jobs_left? So, what is your consideration here?

    Best, CHE Yulin

    opened by CheYulin 1
  • Why use lk.unlock(); in line 151?

    Why use lk.unlock(); in line 151?

    • Could not understand one line of code
      • std::unique_lockstd::mutex lk, the std::unique_lockstd::mutex is designed with RAII, why do you add extra lk.unlock(); in line 151?
      • I am puzzled about that. Could you give me some hints? @nbsdx
    opened by CheYulin 1
  • dynamic `ThreadCount`

    dynamic `ThreadCount`

    Is there a way to make the number of threads (ThreadCount) dynamically used by the program? Something like: ThreadPool pool(std::thread::hardware_concurrency())

    opened by notdodo 1
  • error: could not convert ‘__p.ThreadPool::next_job()::<lambda()>()’ from ‘void’ to ‘bool’

    error: could not convert ‘__p.ThreadPool::next_job()::()’ from ‘void’ to ‘bool’

    I'm getting this error /usr/include/c++/5.3.0/condition_variable: In instantiation of ‘void std::condition_variable::wait(std::unique_lock<std::mutex>&, _Predicate) [with _Predicate = ThreadPool::next_job()::<lambda()>]’: lib/../lib/ThreadPool.hpp:53:78: required from here /usr/include/c++/5.3.0/condition_variable:97:13: error: could not convert ‘__p.ThreadPool::next_job()::<lambda()>()’ from ‘void’ to ‘bool’ while (!__p())

    while using your header with lambda:

    ThreadPool<8> pool;
    pool.AddJob( [it, &l, this]() {
        // Do something
        if (...) {
        }else {...}
        std::lock_guard<std::mutex> lock(this->mtx);
        {...}
    });
    
    opened by notdodo 1
  • Reduce the unnecessary mutex

    Reduce the unnecessary mutex

    The job_available_mutex will unlock after calling the condition_variable::wait, and lock after it return. It means queue_mutex is unnecessary.

    http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex

    opened by 1Feng 1
  • Dead-Lock

    Dead-Lock

    • Hi, nbsdx, I try the following code to use the ThreadPool, but it seemed to be a dead-lock there.
    • I use a script to run the program many times, but it occasionally got stuck.
    • The code I wrote is as follows, which could also be found in my branch.
    • Briefly speaking, I just want to do stage-synchronization-computation, where the inner loop is regarded as a stage.
    • I am not able to solve that.
    • Could you please help me with that? Thanks, CHE Yulin
    #include <thread>
    #include <iostream>
    
    #include "ThreadPool.h"
    
    using std::cout;
    using std::endl;
    
    int main() {
        using namespace nbsdx::concurrent;
        ThreadPool<20> pool;
        for (auto j = 0; j < 3000; j++) {
            cout << "Round:" << j << endl;
            for (int i = 0; i < 5000; ++i) {
                std::function<int(void)> task_function = [i]() {
                    return i * i;
                };
                pool.AddJob(task_function);
            }
            cout << "Finish Add" << endl;
            pool.WaitAll();
        }
    }
    
    opened by CheYulin 4
Owner
Neil
Neil
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

Vladimir (Alkenso) 33 Dec 22, 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

Conor Williams 67 Dec 28, 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

null 1 Apr 22, 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. Features C++ 11 Minimal Source Code Header-only No external depe

Dihara Wijetunga 27 Oct 28, 2022
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 sto

Jakob Progsch 6.1k Jan 7, 2023
Threadpool c++17 - 采用多线程多对列,每个线程控制一个队列,替代老的多个线程公用一个队列

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

黑塞 7 Apr 25, 2022
Single header asymmetric stackful cross-platform coroutine library in pure C.

minicoro Minicoro is single-file library for using asymmetric coroutines in C. The API is inspired by Lua coroutines but with C use in mind. The proje

Eduardo Bart 405 Dec 29, 2022
experimental cooperative threading library for gba in pure C

gba-co-thread Experimental cooperative threading library for Gameboy Advance in pure C. See co_thread.h and co_thread.c for the tiny threading library

Evan Bowman 15 Oct 25, 2022
Lev - Lightweight C++ wrapper for LibEvent 2 API

lev Lightweight C++ wrapper for LibEvent 2 API LibEvent is a great library. It uses a C interface which is well designed but has a learning curve. Thi

Yasser Asmi 46 Sep 15, 2022
Jobxx - Lightweight C++ task system

jobxx License Copyright (c) 2017 Sean Middleditch [email protected] This is free and unencumbered software released into the public domain. A

Sean Middleditch 77 May 28, 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

Han-Kuan Chen 124 Dec 28, 2022
Library of generic and type safe containers in pure C language (C99 or C11) for a wide collection of container (comparable to the C++ STL).

M*LIB: Generic type-safe Container Library for C language Overview M*LIB (M star lib) is a C library enabling to use generic and type safe container i

PpHd 571 Jan 5, 2023
TinyVM is a small, fast, lightweight virtual machine written in pure ANSI C.

TinyVM is a virtual machine with the goal of having a small footprint. Low memory usage, a small amount of code, and a small binary. Building can be

Joseph Kogut 3k Dec 27, 2022
A lightweight, portable pure C99 onnx inference engine for embedded devices with hardware acceleration support.

Libonnx A lightweight, portable pure C99 onnx inference engine for embedded devices with hardware acceleration support. Getting Started The library's

xboot.org 442 Dec 25, 2022
Microshell - a lightweight pure C implementation of shell emulator dedicated for embedded bare-metal systems.

MicroShell Lightweight pure C implementation of virtual shell, compatible with VT100 terminal. Support root tree, run-time mounting paths, global comm

Marcin Borowicz 110 Jan 5, 2023
Graphlite is a lightweight C++ generic graph library

Introduction Graphlite is a lightweight generic graph library that supports node properties edge properties directed/undirected graphs multi-edges & s

null 52 Aug 14, 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

Vladimir (Alkenso) 33 Dec 22, 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

Conor Williams 67 Dec 28, 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

null 1 Apr 22, 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. Features C++ 11 Minimal Source Code Header-only No external depe

Dihara Wijetunga 27 Oct 28, 2022