一个线程池的例子

前几天在B站上看到一个线程池的例子,用到了很多不熟的语法,于是把它记录下来,方便后续慢慢研究。

在windows下用vs2017编译测试过,C++14和C++17都能跑通。

 

直接上代码:

ThreadPool.hpp:

#ifndef __MY_THREAD_POOL_INCLUDE__
#define __MY_THREAD_POOL_INCLUDE__

#include <vector>
#include <mutex>
#include <thread>
#include <chrono>
#include <queue>
#include <condition_variable>
#include <future>
#include <memory>

namespace MyCommSpace
{
    class ThreadPool {
    public:
        ThreadPool(int threadNum);

        // 添加任务到队列中. 注意: -> 表示返回值类型后置。
        template<typename F, typename ...Arg>
        auto enques(F&& f, Arg&& ... arg)->std::future<typename std::result_of<F(Arg...)>::type>;

        ~ThreadPool();
    private:
        void worker(); // 线程的执行内容
        bool isstop = false; // true表示线程池停止
        std::condition_variable cv;
        std::mutex mtx;
        std::vector<std::thread> workers; // 线程集合
        std::queue<std::function<void()>> myque; // 任务队列
    };

    ThreadPool::ThreadPool(int threadNum)
    {
        printf("ThreadPool 创建线程池,线程数量为:%d\n", threadNum);
        for (auto i = 0; i < threadNum; i++)
        {
            workers.emplace_back([this]() {
                this->worker();
            });
        }
    }

    ThreadPool::~ThreadPool()
    {
        printf("~ThreadPool 被析构 ++++++ \n");
        {
            std::unique_lock<std::mutex> mmm(mtx);
            isstop = true;
        }

        cv.notify_all(); // 通知所有阻塞中的线程

        for (auto& one : workers) // 等待所有线程执行完毕
        {
            one.join();
        }
        printf("~ThreadPool 被析构 ------ \n");
    }

    /*
        插入任务队列:
            可以理解f是任务执行的函数
            arg是传递进来的参数
            返回值是: std::future<typename std::result_of<F(Arg...)>::type>  可以由f指定。
    */
    template<typename F, typename ...Arg>
    auto ThreadPool::enques(F&& f, Arg&& ... arg) -> std::future<typename std::result_of<F(Arg...)>::type>
    {
        // 获得f执行后的类型
        using functype = typename std::result_of<F(Arg...)>::type;

        // 获得一个智能指针,指向一个呗包装为 functype()的task
        auto task = std::make_shared<std::packaged_task<functype()>>(
            std::bind(std::forward<F>(f), std::forward<Arg>(arg)...)
            );

        // 获得future
        std::future<functype> rsfuture = task->get_future();

        {
            std::lock_guard<std::mutex> lll(mtx);
            if (isstop)
                throw std::runtime_error("线程池已停止......");

            // 添加任务到队列中
            myque.emplace([task]() {
                (*task)();
            });
        }

        // 通知线程去执行任务
        cv.notify_one();
        return rsfuture;
    }

    void ThreadPool::worker()
    {
        while (1)
        {
            std::function<void()> task; // 定义任务

            {
                // 从队列中取得一个任务
                std::unique_lock<std::mutex> lock(mtx);
                cv.wait(lock, [this] {return this->isstop || !this->myque.empty(); });
                // 注意:实际应用时没必要在 myque.empty() 时返回,后续可以继续添加任务。
                if (isstop && myque.empty())
                    return;
                task = std::move(this->myque.front());
                this->myque.pop();
            }

            // 执行任务
            task();
        }
    }

}
#endif // __MY_THREAD_POOL_INCLUDE__

测试:

main.cpp

#include "ThreadPool.hpp"

int GetSum(int a, int b)
{
    std::cout << "GetSum. ThreadID:" << std::this_thread::get_id() << std::endl;
    return a + b;
}

void threadTest()
{
    MyCommSpace::ThreadPool mypool(4);

    for (auto i = 0; i < 30; i++)
    {
#if 1
        auto rsfuture0 = mypool.enques([](int a, int b) ->int {
            std::cout << "ThreadID:" << std::this_thread::get_id() << std::endl;
            return a + b; }, 10 * i, 10 * i);
        std::cout << "thread rs:" << rsfuture0.get() << std::endl;
#else
        // 上述lamda表达式可以写成下面这样,便于理解。
        auto rsfuture0 = mypool.enques(&GetSum, 10 * i, 10 * i);
        std::cout << "thread rs:" << rsfuture0.get() << std::endl;
#endif 
    }
}

int main()
{
    threadTest();
    return 0;
}

 

结果:

可以看到只有4个线程在跑

 

总结:

posted @ 2024-09-24 15:33  xcywt  阅读(17)  评论(0编辑  收藏  举报
作者:xcywt
出处:https://www.cnblogs.com/xcywt//
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。