C++线程池实现与解析(100行简洁实现)

C++线程池

自定义一个线程池类,使用有参构造函数实现线程的创建和任务的执行。

析构函数中,设置stop=Ture,并且通知所有线程。

github链接:包含pdf解析+完整代码
https://github.com/COPELONG/Cpp-ThreadPool/tree/master

觉得有帮助点个star呦~~

1.万能引用:

格式:模板 &&。发生类型推导,推导规则:引用折叠。
在这里插入图片描述在这里插入图片描述

2.完美转发:

传入的参数以前是左值或者右值,经过转发,再次传入也是原来的类型。
在这里插入图片描述

标准库提供了函数模板:

在这里插入图片描述在这里插入图片描述

3.bind机制:

绑定,函数与参数绑定在一起,形成新的对象.

void add(int x, int y ,int z){}
auto  a = std::bind(add , 1, 2, 3);
a();

4.bind与完美转发结合使用:

避免了不必要的拷贝和转换,同时也保持了类型的准确性。接受各种类型的函数对象和参数,并正确地将它们绑定在一起。

template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) 
{
   return std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}

/ 调用 enqueue 传递一个普通函数指针和参数
int add(int a, int b) { return a + b; }
ThreadPool pool;
auto future1 = pool.enqueue(add, 3, 5);

// 调用 enqueue 传递一个 lambda 表达式和参数
ThreadPool pool;
auto future2 = pool.enqueue([](int x, int y) { return x * y; }, 4, 6);

// 定义一个函数对象类
struct MyFunctionObject {
    int operator()(int x, int y) { return x - y; }
};
ThreadPool pool;
MyFunctionObject myFuncObj;
auto future3 = pool.enqueue(myFuncObj, 8, 2);

5.furture:

提供了一种等待异步任务完成并获取结果的方法。

std::packaged_task<int()> 是一个模板类,它用于包装一个可调用对象(函数或者函数对象),并且可以异步执行这个可调用对象.

可以使用 std::packaged_task<int()> 来封装一个函数或者 lambda 表达式.

#include <iostream>
#include <future>
#include <functional>

int add(int a, int b) {
    return a + b;
}

int main() {
    std::packaged_task<int()> task(std::bind(add, 3, 5));
    std::future<int> result = task.get_future();

    // 启动异步任务
    std::thread th(std::move(task));
    th.join();

    // 获取异步任务的结果
    int sum = result.get();
    std::cout << "Sum: " << sum << std::endl;

    return 0;
}

使用 std::future 时,可以通过 std::future::get() 方法获取异步操作的结果。这个方法会阻塞当前线程,直到异步任务完成并返回结果。如果异步任务尚未完成,get() 方法将等待直到任务完成并返回结果。

std::packaged_task //是一个可调用对象,可以将函数和其参数打包成一个异步任务。
std::function<void()>://表示一个可调用对象(函数、函数对象、lambda 表达式等)的类型,它可以保存任意可调用对象,并提供了一种统一的方式来调用这些对象。    
    
auto task = std::make_shared< std::packaged_task<int()> >//即使 int() 没有参数,std::bind 仍然可以绑定带有参数的函数,
(
    std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);//将绑定后的 std::packaged_task 对象放入智能指针 task 中,以便能够在将来的某个时间点执行该任务。
using result_type = typename result_of<F(Args...)>::type;//获取函数的返回值
future<result_type> res = task->get_future();//异步对象,返回的类型是future<函数返回值类型>
res.get()//等待task()执行,get获取。

完整代码实现:

线程池头文件:

#ifndef PTHREAD_POOL_H
#define PTHREAD_POOL_H

#include <thread>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <queue>
#include <vector>
#include <stdexcept>
using namespace std;

class Thread_Pool
{
public:
    Thread_Pool(size_t size);

    ~Thread_Pool();

    template <class F, class... Args>
    auto enqueue(F &&f, Args &&...args) -> future<typename std::result_of<F(Args...)>::type>;

private:
    thread t;
    bool stop;
    vector<thread> m_worker;
    queue<function<void()>> m_tasks;
    mutex m_mutex;
    condition_variable m_cond;
};

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

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

    future<result_type> res = task->get_future();

    {
        unique_lock<mutex> lock(m_mutex);
        if (stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");
        m_tasks.emplace(
            [task]()
            {
                (*task)();
            });
    }
    m_cond.notify_one();
    return res;
}
Thread_Pool::Thread_Pool(size_t size) : stop(false)
{
    for (int i = 0; i < size; i++)
    {
        m_worker.emplace_back(
            [this]()
            {
                std::function<void()> task;
                while (true)
                {
                    {
                        unique_lock<mutex> lock(m_mutex);
                        m_cond.wait(lock, [this]
                                    { return stop || !m_tasks.empty(); });
                        if (stop && m_tasks.empty())
                            return;
                        task = std::move(this->m_tasks.front());
                        m_tasks.pop();
                    }
                    task();
                }
            });
    }
}

Thread_Pool::~Thread_Pool()
{
    {
        std::unique_lock<mutex> lock(m_mutex);
        stop = true;
    }
    m_cond.notify_all();
    for (std::thread &worker : m_worker)
        worker.join();
}

#endif

main.cpp:测试

#include <iostream>
#include <vector>
#include <chrono>

#include "Thread.h"

int main()
{
    
    Thread_Pool pool(4);
    std::vector< std::future<int> > results;

    for(int i = 0; i < 8; ++i) {
        results.emplace_back(
            pool.enqueue([i] {
                std::cout << "hello " << i << std::endl;
                std::this_thread::sleep_for(std::chrono::seconds(1));
                std::cout << "world " << i << std::endl;
                return i*i;
            })
        );
    }

    for(auto && result: results)
        std::cout << result.get() << ' ';
    std::cout << std::endl;
    
    return 0;
}

参考链接:
[1] github:https://github.com/progschj/ThreadPool

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值