multithreading – C ++ General purpose thread pool of fixed size


I have been reading for a few days on thread pools in C ++ and I decided to deploy mine. I mainly intend to use it to learn how to implement parallel algorithms at some point in the future, but before that, I need to know if I can do something to make it more efficient. .

These are all the variables I use. I decided to put everything in its own namespace and do the std::condition_variable (responsible for the main thread break) static because there is really no need for each thread_pool object to having a copy.

namespace async {

    static std::condition_variable main_thread_cv;

    template 
    class thread_pool {

        private:
            std::mutex mutex_m;
            std::atomic busy_m;
            std::condition_variable pool_cv_m;
            std::array workers_m;
            std::queue> task_queue_m;
            bool should_terminate_m;
            void thread_loop();

        public:
            thread_pool();
            ~thread_pool();
            thread_pool(const thread_pool& other) = delete;
            thread_pool(const thread_pool&& other) = delete;
            thread_pool& operator=(const thread_pool& other) = delete;
            thread_pool& operator=(const thread_pool&& other) = delete;
            void wait();
            template  void enqueue(Fn&& function, Args&&... args);

    };
...
}

This is the thread loop executed by all of the worker threads.

template
void thread_pool::thread_loop() {

    thread_local std::function task;

    for (;;) {
        { std::unique_lock lock(mutex_m);
            pool_cv_m.wait(lock, (this)() { return !task_queue_m.empty() || should_terminate_m; });
            if (should_terminate_m) {
                break;
            }
            task = task_queue_m.front();
            task_queue_m.pop();
        }
        busy_m++;
        task();
        busy_m--;
        main_thread_cv.notify_one();
    }

}

ctor and dtor:

template
thread_pool::thread_pool() {

    busy_m = 0;
    should_terminate_m = false;

    for (auto& thread : workers_m) {
        thread = std::thread((this)() { thread_loop(); });
    }

}

template
thread_pool::~thread_pool() {

    busy_m = 0;
    should_terminate_m = true;

    pool_cv_m.notify_all();

    for (auto& thread : workers_m) {
        thread.join();
    }

}

the wait and enqueue the functions:

template
void thread_pool::wait() {

    { std::unique_lock lock(mutex_m);
        main_thread_cv.wait(lock, (this)() { return busy_m == 0 && task_queue_m.empty(); });
    }

}

template
template
void thread_pool::enqueue(Fn&& function, Args&& ...args) {

    { std::scoped_lock lock(mutex_m);
        task_queue_m.push(std::bind(std::forward(function), std::forward(args)...));
        pool_cv_m.notify_one();
    }

}