#include <iostream>
#include <thread>
#include <deque>
#include <functional>
#include <future>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <memory>

class ZYLThreadPool {
public:
    ZYLThreadPool(size_t maxThreads = 200): _maxThreads(maxThreads), _stop(false) {
        worker_threads.reserve(_maxThreads);
        for(size_t i = 0; i < _maxThreads; ++i) {
            worker_threads.emplace_back([this] {
                for(;;) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->_mutex);
                        this->_condVar.wait(lock, [this] {
                            return this->_stop || !this->_taskQueue.empty();
                        });
                        if(this->_stop && this->_taskQueue.empty()) return;
                        task = std::move(this->_taskQueue.front());
                        this->_taskQueue.pop_front();
                    }
                    task();
                }
            });
        }
    }

    template<typename F, typename... Args>
    auto submit(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
        using return_type = typename std::result_of<F(Args...)>::type;

        auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));

        std::future<return_type> result = task->get_future();
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_stop) {
                throw std::runtime_error("Submit on stopped ZYLThreadPool");
            }
            _taskQueue.emplace_back([task] { (*task)(); });
        }
        _condVar.notify_one();
        return result;
    }

    void cancel() {
        std::unique_lock<std::mutex> lock(_mutex);
        if (!_stop) {
            _stop = true;
            _condVar.notify_all();
        }
        for(std::thread &worker: worker_threads) worker.join();
    }

    size_t getNumTasks() {
        std::unique_lock<std::mutex> lock(_mutex);
        return _taskQueue.size();
    }

    ~ZYLThreadPool() {
        cancel();
    }

private:
    std::vector<std::thread> worker_threads;
    std::deque<std::function<void()>> _taskQueue;
    size_t _maxThreads;
    std::mutex _mutex;
    std::condition_variable _condVar;
    bool _stop;
};


class Test {
public:
    Test(double devid): _devid(devid), _running(true) {
    }

    void start(ZYLThreadPool &threadPool) {
        _future = threadPool.submit(&Test::_task, this);
    }

    void stop() {
        {
			_running = false;
            std::unique_lock<std::mutex> lock(_mutex);
            
            if (_future.valid()) {
                _future.get();
                lock.unlock();
                _cleanupResources();
            }
        }
    }

private:
    std::mutex _mutex;
    double _devid;
    std::deque<double> _dequeue_packets;
    std::future<void> _future;
    bool _running;

    void _cleanupResources() {
        std::unique_lock<std::mutex> lock(_mutex);
        _dequeue_packets.clear();
    }

    void _task() {
        std::unique_lock<std::mutex> lock(_mutex);
        while(_running ) {
			if (_dequeue_packets.empty()){
				 std::cout<<"unning task"<<std::endl;
				continue;
			}
            double packet = _dequeue_packets.front();
            _dequeue_packets.pop_front();
            lock.unlock();
            std::cout<<"running task"<<std::endl;
            lock.lock();
        }
		std::cout<<"task end"<<std::endl;
    }
};

int main() {
    ZYLThreadPool zylThreadPool(200);
    std::shared_ptr<Test> test = std::make_shared<Test>(1.0);
    
    test->start(zylThreadPool);
    std::this_thread::sleep_for(std::chrono::seconds(3));
	std::cout<<"stop task"<<std::endl;
    test->stop();

    return 0;
}

上面例子，测试程序启动过后，发现就已经是默认启了201个线程，请完善，要求：
1.在线程池初始化时默认不会创建所有的线程，而是先创建一些线程，比如20个
2.能够根据实际情况自动调整线程的数量，比如，常用的线程池实现中，可以指定线程池的最大容量为200，最小容量为20
3.线程池启动时会创建最小容量的线程，如果当前任务量较大，线程池就会根据需要增加线程数，直到达到最大容量
4.如果当前任务量较少，线程池就会逐渐减少线程数，直到最小容量
5.需要动态创建线程，避免资源浪费或者线程数过少导致性能瓶颈
6.请晚上测试demo,要求动态添加100个test任务，然后动态停止100个test任务，然后再启动3个test任务来观察测试