#include "ThreadPool.h"
#include <stdexcept>
#include <cstdio>

// 获取单例实例
ThreadPool &ThreadPool::GetInstance()
{
    static ThreadPool instance(3); // 固定3个工作线程
    return instance;
}

ThreadPool::~ThreadPool()
{
    shutdown();
}

void ThreadPool::shutdown()
{
    printf("ThreadPool destroyed\n");
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
        // 清空所有线程的任务队列
        for (auto &queue : threadTasks)
        {
            // 使用swap技巧清空队列
            std::queue<std::function<void()>> empty;
            std::swap(queue, empty);
        }
    }

    // 通知所有线程
    for (auto &cond : threadConditions)
        cond->notify_all();

    for (std::thread &worker : workers)
        if (worker.joinable())
            worker.join();

    // 释放条件变量
    for (auto &cond : threadConditions)
        delete cond;
}

// 获取线程池大小
size_t ThreadPool::size() const
{
    return workers.size();
}

// 获取指定线程的负载（待处理任务数）
size_t ThreadPool::getThreadLoad(int threadId) const
{
    if (threadId < 0 || threadId >= static_cast<int>(workers.size()))
        throw std::runtime_error("Invalid thread ID");

    std::unique_lock<std::mutex> lock(queue_mutex);
    return threadTasks.at(threadId).size();
}

// 私有构造函数实现
ThreadPool::ThreadPool(size_t numThreads) : stop(false)
{
    // 为每个线程创建任务队列
    threadTasks.resize(numThreads);

    // 为每个线程创建条件变量
    for (size_t i = 0; i < numThreads; ++i)
    {
        threadConditions.push_back(new std::condition_variable());
    }

    for (size_t i = 0; i < numThreads; ++i)
    {
        workers.emplace_back([this, i]
                             {
            while(true) {
                std::function<void()> task;
                
                {
                    std::unique_lock<std::mutex> lock(this->queue_mutex);
                    this->threadConditions[i]->wait(lock, [this, i] {
                        return this->stop || !this->threadTasks[i].empty();
                    });
                    
                    if(this->stop && this->threadTasks[i].empty())
                        return;
                        
                    task = std::move(this->threadTasks[i].front());
                    this->threadTasks[i].pop();
                }
                
                task();
            } });
    }
}
