vector of threads thread pool c++

#include <iostream>
#include <vector>
#include <thread>
#include <functional>
#include <mutex>
#include <queue>
#include <condition_variable>

class ThreadPool {
public:
    ThreadPool(size_t num_threads) : stop(false) {
        for (size_t i = 0; i < num_threads; ++i) {
            workers.emplace_back(
                [this] {
                    while (true) {
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lock(queue_mutex);
                            condition.wait(lock, [this] { return stop || !tasks.empty(); });
                            if (stop && tasks.empty()) {
                                return;
                            }
                            task = std::move(tasks.front());
                            tasks.pop();
                        }
                        task();
                    }
                }
            );
        }
    }

    template<class F, class... Args>
    void enqueue(F&& f, Args&&... args) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            tasks.emplace([f, args...]() { f(args...); });
        }
        condition.notify_one();
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& worker : workers) {
            worker.join();
        }
    }

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;
};

void example_function(int id) {
    std::cout << "Hello from thread " << id << std::endl;
}

int main() {
    ThreadPool pool(4); // Creating a pool with 4 worker threads

    // Enqueue tasks to the thread pool
    for (int i = 0; i < 8; ++i) {
        pool.enqueue(example_function, i);
    }

    // All tasks have been enqueued, destructor will join threads when finished
    return 0;
}

This code implements a basic thread pool in C++. The ThreadPool class manages a collection of worker threads. It initializes a specified number of threads upon creation. Tasks can be enqueued using the enqueue method, which takes a callable object (function or lambda) along with its arguments. The worker threads continuously check for tasks in the queue and execute them when available. The stop flag is used to signal the threads to stop processing tasks and exit gracefully when the pool is destroyed. The example demonstrates the usage of the thread pool by enqueuing tasks in the main function.