线程池的实现和c++的语法,包含使用例子,加一些错误点(lamda)笔记

##错误写法

#include <vector>
#include <string>
#include <functional>
#include <iostream>
#include <future>
#include <thread>
#include <condition_variable>
#include <chrono>
#include <mutex>
#include <queue>

using namespace std;
class ThreadPool {
public:
    ThreadPool():m_nthread(2),m_bstop(false){ //默认两个线程
        for (int i = 0; i < m_nthread; ++i)
        {
            m_vecthread.emplace_back([this]() {
                while (1)
                {
                    std::function<void()>func;
                    {
                        std::unique_lock<std::mutex> lck(m_mtx);
                        m_cv.wait(lck, [&]() {
                            return m_quetasks.size() > 0 || m_bstop;
                            });
                        if (m_quetasks.size() == 0 && m_bstop)
                            break;
                        func = m_quetasks.front();
                        m_quetasks.pop();
                    }
                    func();
                }
            });
        } 
    }

    ThreadPool(int n):m_nthread(n),m_bstop(false){
        for (int i = 0; i < m_nthread; ++i)
        {
            m_vecthread.emplace_back([this]() {
                while (1)
                {
                    std::function<void()>func;
                    {
                        std::unique_lock<std::mutex> lck(m_mtx);
                        m_cv.wait(lck, [&]() {
                            return m_quetasks.size() > 0||m_bstop;//有任务,就算stop了,也要继续将剩下的任务完成
                            });
                        if (m_quetasks.size() == 0 && m_bstop)
                            break;
                        func = m_quetasks.front();
                        m_quetasks.pop();
                    }
                    func();
                }
            });
        }
    }

    virtual ~ThreadPool() {
        m_bstop = true;
        m_cv.notify_all();
        for (auto& it : m_vecthread)
        {
            if (it.joinable())
                it.join();
        }
    }

template<class F,class ...Args>
auto Enqueue(F&& f, Args&& ...args)->std::future<std::_Invoke_result_t<F,Args...>>
{
    using return_type = std::_Invoke_result_t<F, Args...>;
    std::packaged_task<return_type()> ptask(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    std::future<return_type>res = ptask.get_future();

    {
        std::unique_lock<std::mutex>lck(m_mtx);
        if (m_bstop)
            throw std::runtime_error("线程池已经停止,不可加入数据");
        m_quetasks.emplace([&]() {//!!!错误,当真正调用的时候,
        //&保存的早就已经失效了,应当使用指针的形式
            ptask();
            });
    }
    m_cv.notify_one();
    return res;
}


private:
    int m_nthread;
    bool m_bstop;
    std::queue<std::function<void()>> m_quetasks;
    std::vector<std::thread>m_vecthread;
    std::condition_variable m_cv;
    std::mutex m_mtx;
};

int testPool(int i, int j)
{
    return i + j;
}

int main()
{
    ThreadPool pool(5);
    std::vector<std::future<int>>vecRes;
    for (int i = 1; i <= 20; ++i)
    {
        vecRes.emplace_back(pool.Enqueue(testPool, 0, i));
    }
    
    for (auto &&it : vecRes)
    {
        std::cout<<it.get()<<std::endl;
    }
    
    std::cout << "Hello World!\n";
}

//正确写法,使用智能指针,lamda表达式一定要注意生命周期
//尤其是写入vector这种容器内,后面取出来用的这种!!!

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

using namespace std;
class ThreadPool {
public:
    ThreadPool():m_nthread(2),m_bstop(false){ //默认两个线程
        for (int i = 0; i < m_nthread; ++i)
        {
            m_vecthread.emplace_back([this]() {
                while (1)
                {
                    std::function<void()>func;
                    {
                        std::unique_lock<std::mutex> lck(m_mtx);
                        m_cv.wait(lck, [&]() {
                            return m_quetasks.size() > 0 || m_bstop;
                            });
                        if (m_quetasks.size() == 0 && m_bstop)
                            break;
                        func = m_quetasks.front();
                        m_quetasks.pop();
                    }
                    func();
                }
            });
        } 
    }

    ThreadPool(int n):m_nthread(n),m_bstop(false){
        for (int i = 0; i < m_nthread; ++i)
        {
            m_vecthread.emplace_back([this]() {
                while (1)
                {
                    std::function<void()>func;
                    {
                        std::unique_lock<std::mutex> lck(m_mtx);
                        m_cv.wait(lck, [&]() {
                            return m_quetasks.size() > 0||m_bstop;//有任务,就算stop了,也要继续将剩下的任务完成
                            });
                        if (m_quetasks.size() == 0 && m_bstop)
                            break;
                        func = m_quetasks.front();
                        m_quetasks.pop();
                    }
                    func();
                }
            });
        }
    }

    virtual ~ThreadPool() {
        m_bstop = true;
        m_cv.notify_all();
        for (auto& it : m_vecthread)
        {
            if (it.joinable())
                it.join();
        }
    }

template<class F,class ...Args>
auto Enqueue(F&& f, Args&& ...args)->std::future<std::_Invoke_result_t<F,Args...>>
{
    using return_type = std::_Invoke_result_t<F, Args...>;
    std::shared_ptr<std::packaged_task<return_type()>> ptask=std::make_shared<std::packaged_task<return_type()>>
        (std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    std::future<return_type>res = ptask->get_future();
    {
        std::unique_lock<std::mutex>lck(m_mtx);
        if (m_bstop)
            throw std::runtime_error("线程池已经停止,不可加入数据");
        m_quetasks.emplace([ptask]() {
            (*ptask)();
            });
    }
    m_cv.notify_one();
    return res;
}


private:
    int m_nthread;
    bool m_bstop;
    std::queue<std::function<void()>> m_quetasks;
    std::vector<std::thread>m_vecthread;
    std::condition_variable m_cv;
    std::mutex m_mtx;
};

int testPool(int i, int j)
{
    return i + j;
}

int main()
{
    ThreadPool pool(5);
    std::vector<std::future<int>>vecRes;
    for (int i = 1; i <= 20; ++i)
    {
        vecRes.emplace_back(pool.Enqueue(testPool, 0, i));
    }
    
    for (auto &&it : vecRes)
    {
        std::cout<<it.get()<<std::endl;
    }
    
    std::cout << "Hello World!\n";
}

lamda表达式,如果使用值捕获(= or 变量名),就是执行了复制操作创建了一个副本,
如果使用引用,就是对外部变量进行引用。也可以进行移动对象的操作,std::move。
如果需要在lamda表达式中使用不可复制对象,且被删除的对象时,
可以使用智能指针的形式。例如上面的package_task对象,不可复制,可移动(future对象
一样),使用智能指针的形式来调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值