当前位置: 首页 > article >正文

C++11实现线程库

本篇博客通过packaged_task 封装一个可以让用户拿到线程结果的线程池。
packaged_task 可以封装模板类,可以封装一个函数,模板类型是该函数的返回值类型,可以通过get_future 获得future来获得函数的返回值。该线程池最终的一个函数就是想线程池中push任务的函数,用户可以自己要执行的函数以及参数传递进来,然后线城池启动线程进行执行,通过函数返回值的方式让用户拿到数据。因为用户要执行的参数个数类型是不确定的,所以该函数是一个模板函数,第一个模板参数是要执行的函数,第二个是可变参数模板,用来接收用户的参数,在函数内部通过绑定参数,来得到一个无参的可执行对象,通过构造lambda的方式来添加进入任务队列。具体代码如下:

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

class ThreadPool
{
    using Functor = std::function<void()>;
public:
    ThreadPool(int threadnum = 5) : _stop(false)
    {
        for(int i = 0; i < threadnum; ++i)
        {
            _threads.emplace_back(std::thread(&ThreadPool::entry, this));
        }
    }

    // 对任务进行封装packaged_task,使用lambda传入任务池
    template<typename F, typename ...Args>
    auto push(F&& f, Args&& ...args) -> std::future<decltype(f(args...))>
    {
        // 获取返回值类型
        using return_type = decltype(f(args...));
        // 把参数进行绑定
        auto fun = std::bind(&std::forward<F>(f), std::forward<Args>(args)...);
        // 封装成为packaged_task 指针, 一定要构建堆上的对象
        auto pack_task_ptr = std::make_shared<std::packaged_task<return_type()>>(fun);
        // 获取返回值
        std::future<return_type> res = pack_task_ptr->get_future();
        // 加锁
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 封装成为lambda 加入到任务池
             _funcs.emplace_back([pack_task_ptr](){ (*pack_task_ptr)(); });
        }
		// 唤醒所有线程
        _con.notify_all();
        return res;
    }

    void stop()
    {
        _stop = true;
        _con.notify_all();
        for(auto& th : _threads)
        {
            th.join();
        }
    }

    ~ThreadPool()
    {
        stop();
    }
private:
    // 线程的入口函数
    void entry() 
    {
        while(!_stop)
        {
        	// 临时变量,一次拿到所有的任务,一下全部执行,避免频繁的加锁解锁
            std::vector<Functor> tmp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // while(!_stop && _funcs.empty())_con.wait(lock);
                _con.wait(lock, [this](){ return _stop || !_funcs.empty();});

                tmp.swap(_funcs);
            }

            for(auto task : tmp)
            {
                task();
            }
        }
    }
private:
    std::atomic<bool> _stop; // 表示线城池是否停止了
    std::mutex _mutex; //互斥锁
    std::condition_variable _con; // 条件变量 
    std::vector<Functor> _funcs;  // 任务池
    std::vector<std::thread> _threads; // 管理的线程
};

http://www.kler.cn/a/398467.html

相关文章:

  • 针对股票评论的情感分类器
  • LLMs 训练经验篇
  • 游戏引擎学习第八天
  • 数据结构(初阶4)---循环队列详解
  • 详解map与multimap容器
  • 阿里云ACK容器如何配置pod分散在集群的不同节点上
  • 21.3D surface
  • Python 子进程输出重定向以后,部分内容会出现在父进程的控制台屏幕上
  • .NET 一款SYSTEM权限隐藏的计划任务工具
  • vxe-grid table 校验指定行单元格的字段,只校验某个列的字段
  • Leetcode 3356. Zero Array Transformation II
  • uni-app快速入门(六)--rpx尺寸单位与Flex布局
  • 【网络安全面经】OSI七层模型每层都有什么协议
  • 【网络安全】SSL(一):为什么需要 Keyless SSL?
  • 023、ELK 从入门到实践
  • 【AI日记】24.11.17 看 GraphRAG 论文,了解月之暗面
  • 深度学习中常见的学习率调整策略
  • 蓝桥杯c++算法学习【4】之简单数论(阶乘约数、求值、循环小数、等差数列、最大比例:::非常典型的必刷例题!!!)
  • PyCharm2024.2.4安装
  • 【初阶数据结构与算法】链表刷题之链表分割、相交链表、环形链表1、环形链表I、环形链表II
  • Ajax获取PHP端csv转的json数据并js前端排序与分页
  • 华东师范大学数学分析第五版PDF习题答案上册及下册
  • 第二十三章 TCP 客户端 服务器通信 - SSL TLS组件
  • java实现代码沙盒(docker-java)
  • 基于neo4j的体育运动员问答问答系统
  • 遇到 mysql_config not found 错误